Drizzled Public API Documentation

data0data.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /********************************************************************/
00026 #include "data0data.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "data0data.ic"
00030 #endif
00031 
00032 #ifndef UNIV_HOTBACKUP
00033 #include "rem0rec.h"
00034 #include "rem0cmp.h"
00035 #include "page0page.h"
00036 #include "page0zip.h"
00037 #include "dict0dict.h"
00038 #include "btr0cur.h"
00039 
00040 #include <ctype.h>
00041 #endif /* !UNIV_HOTBACKUP */
00042 
00043 #ifdef UNIV_DEBUG
00044 
00047 UNIV_INTERN byte  data_error;
00048 
00049 # ifndef UNIV_DEBUG_VALGRIND
00050 
00051 UNIV_INTERN ulint data_dummy;
00052 # endif /* !UNIV_DEBUG_VALGRIND */
00053 #endif /* UNIV_DEBUG */
00054 
00055 #ifndef UNIV_HOTBACKUP
00056 /*********************************************************************/
00059 UNIV_INTERN
00060 ibool
00061 dfield_data_is_binary_equal(
00062 /*========================*/
00063   const dfield_t* field,  
00064   ulint   len,  
00065   const byte* data) 
00066 {
00067   if (len != dfield_get_len(field)) {
00068 
00069     return(FALSE);
00070   }
00071 
00072   if (len == UNIV_SQL_NULL) {
00073 
00074     return(TRUE);
00075   }
00076 
00077   if (0 != memcmp(dfield_get_data(field), data, len)) {
00078 
00079     return(FALSE);
00080   }
00081 
00082   return(TRUE);
00083 }
00084 
00085 /************************************************************/
00089 UNIV_INTERN
00090 int
00091 dtuple_coll_cmp(
00092 /*============*/
00093   const dtuple_t* tuple1, 
00094   const dtuple_t* tuple2) 
00095 {
00096   ulint n_fields;
00097   ulint i;
00098 
00099   ut_ad(tuple1 && tuple2);
00100   ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
00101   ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
00102   ut_ad(dtuple_check_typed(tuple1));
00103   ut_ad(dtuple_check_typed(tuple2));
00104 
00105   n_fields = dtuple_get_n_fields(tuple1);
00106 
00107   if (n_fields != dtuple_get_n_fields(tuple2)) {
00108 
00109     return(n_fields < dtuple_get_n_fields(tuple2) ? -1 : 1);
00110   }
00111 
00112   for (i = 0; i < n_fields; i++) {
00113     int   cmp;
00114     const dfield_t* field1  = dtuple_get_nth_field(tuple1, i);
00115     const dfield_t* field2  = dtuple_get_nth_field(tuple2, i);
00116 
00117     cmp = cmp_dfield_dfield(field1, field2);
00118 
00119     if (cmp) {
00120       return(cmp);
00121     }
00122   }
00123 
00124   return(0);
00125 }
00126 
00127 /*********************************************************************/
00130 UNIV_INTERN
00131 void
00132 dtuple_set_n_fields(
00133 /*================*/
00134   dtuple_t* tuple,    
00135   ulint   n_fields) 
00136 {
00137   ut_ad(tuple);
00138 
00139   tuple->n_fields = n_fields;
00140   tuple->n_fields_cmp = n_fields;
00141 }
00142 
00143 /**********************************************************/
00146 static
00147 ibool
00148 dfield_check_typed_no_assert(
00149 /*=========================*/
00150   const dfield_t* field)  
00151 {
00152   if (dfield_get_type(field)->mtype > DATA_MYSQL
00153       || dfield_get_type(field)->mtype < DATA_VARCHAR) {
00154 
00155     fprintf(stderr,
00156       "InnoDB: Error: data field type %lu, len %lu\n",
00157       (ulong) dfield_get_type(field)->mtype,
00158       (ulong) dfield_get_len(field));
00159     return(FALSE);
00160   }
00161 
00162   return(TRUE);
00163 }
00164 
00165 /**********************************************************/
00168 UNIV_INTERN
00169 ibool
00170 dtuple_check_typed_no_assert(
00171 /*=========================*/
00172   const dtuple_t* tuple)  
00173 {
00174   const dfield_t* field;
00175   ulint   i;
00176 
00177   if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
00178     fprintf(stderr,
00179       "InnoDB: Error: index entry has %lu fields\n",
00180       (ulong) dtuple_get_n_fields(tuple));
00181 dump:
00182     fputs("InnoDB: Tuple contents: ", stderr);
00183     dtuple_print(stderr, tuple);
00184     putc('\n', stderr);
00185 
00186     return(FALSE);
00187   }
00188 
00189   for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
00190 
00191     field = dtuple_get_nth_field(tuple, i);
00192 
00193     if (!dfield_check_typed_no_assert(field)) {
00194       goto dump;
00195     }
00196   }
00197 
00198   return(TRUE);
00199 }
00200 #endif /* !UNIV_HOTBACKUP */
00201 
00202 #ifdef UNIV_DEBUG
00203 /**********************************************************/
00206 UNIV_INTERN
00207 ibool
00208 dfield_check_typed(
00209 /*===============*/
00210   const dfield_t* field)  
00211 {
00212   if (dfield_get_type(field)->mtype > DATA_MYSQL
00213       || dfield_get_type(field)->mtype < DATA_VARCHAR) {
00214 
00215     fprintf(stderr,
00216       "InnoDB: Error: data field type %lu, len %lu\n",
00217       (ulong) dfield_get_type(field)->mtype,
00218       (ulong) dfield_get_len(field));
00219 
00220     ut_error;
00221   }
00222 
00223   return(TRUE);
00224 }
00225 
00226 /**********************************************************/
00229 UNIV_INTERN
00230 ibool
00231 dtuple_check_typed(
00232 /*===============*/
00233   const dtuple_t* tuple)  
00234 {
00235   const dfield_t* field;
00236   ulint   i;
00237 
00238   for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
00239 
00240     field = dtuple_get_nth_field(tuple, i);
00241 
00242     ut_a(dfield_check_typed(field));
00243   }
00244 
00245   return(TRUE);
00246 }
00247 
00248 /**********************************************************/
00252 UNIV_INTERN
00253 ibool
00254 dtuple_validate(
00255 /*============*/
00256   const dtuple_t* tuple)  
00257 {
00258   const dfield_t* field;
00259   ulint   n_fields;
00260   ulint   len;
00261   ulint   i;
00262 
00263   ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
00264 
00265   n_fields = dtuple_get_n_fields(tuple);
00266 
00267   /* We dereference all the data of each field to test
00268   for memory traps */
00269 
00270   for (i = 0; i < n_fields; i++) {
00271 
00272     field = dtuple_get_nth_field(tuple, i);
00273     len = dfield_get_len(field);
00274 
00275     if (!dfield_is_null(field)) {
00276 
00277       const byte* data = dfield_get_data(field);
00278 #ifndef UNIV_DEBUG_VALGRIND
00279       ulint   j;
00280 
00281       for (j = 0; j < len; j++) {
00282 
00283         data_dummy  += *data; /* fool the compiler not
00284                   to optimize out this
00285                   code */
00286         data++;
00287       }
00288 #endif /* !UNIV_DEBUG_VALGRIND */
00289 
00290       UNIV_MEM_ASSERT_RW(data, len);
00291     }
00292   }
00293 
00294   ut_a(dtuple_check_typed(tuple));
00295 
00296   return(TRUE);
00297 }
00298 #endif /* UNIV_DEBUG */
00299 
00300 #ifndef UNIV_HOTBACKUP
00301 /*************************************************************/
00303 UNIV_INTERN
00304 void
00305 dfield_print(
00306 /*=========*/
00307   const dfield_t* dfield) 
00308 {
00309   ulint   i;
00310 
00311   ulint len = dfield_get_len(dfield);
00312   const byte *data = static_cast<const byte *>(dfield_get_data(dfield));
00313 
00314   if (dfield_is_null(dfield)) {
00315     fputs("NULL", stderr);
00316 
00317     return;
00318   }
00319 
00320   switch (dtype_get_mtype(dfield_get_type(dfield))) {
00321   case DATA_CHAR:
00322   case DATA_VARCHAR:
00323     for (i = 0; i < len; i++) {
00324       int c = *data++;
00325       putc(isprint(c) ? c : ' ', stderr);
00326     }
00327 
00328     if (dfield_is_ext(dfield)) {
00329       fputs("(external)", stderr);
00330     }
00331     break;
00332   case DATA_INT:
00333     ut_a(len == 4); /* only works for 32-bit integers */
00334     fprintf(stderr, "%d", (int)mach_read_from_4(data));
00335     break;
00336   default:
00337     ut_error;
00338   }
00339 }
00340 
00341 /*************************************************************/
00344 UNIV_INTERN
00345 void
00346 dfield_print_also_hex(
00347 /*==================*/
00348   const dfield_t* dfield) 
00349 {
00350   const byte* data;
00351   ulint   len;
00352   ulint   prtype;
00353   ulint   i;
00354   ibool   print_also_hex;
00355 
00356   len = dfield_get_len(dfield);
00357   data = static_cast<const byte *>(dfield_get_data(dfield));
00358 
00359   if (dfield_is_null(dfield)) {
00360     fputs("NULL", stderr);
00361 
00362     return;
00363   }
00364 
00365   prtype = dtype_get_prtype(dfield_get_type(dfield));
00366 
00367   ib_id_t id= 0;
00368         ulint val= 0;
00369   static const ulint UNSIGNED_MASK= 0x80000000;
00370 
00371   switch (dtype_get_mtype(dfield_get_type(dfield))) {
00372   case DATA_INT:
00373     switch (len) {
00374     case 1:
00375       val = mach_read_from_1(data);
00376 
00377       if (!(prtype & DATA_UNSIGNED)) {
00378         val &= ~0x80;
00379         fprintf(stderr, "%ld", (long) val);
00380       } else {
00381         fprintf(stderr, "%lu", (ulong) val);
00382       }
00383       break;
00384 
00385     case 2:
00386       val = mach_read_from_2(data);
00387 
00388       if (!(prtype & DATA_UNSIGNED)) {
00389         val &= ~0x8000;
00390         fprintf(stderr, "%ld", (long) val);
00391       } else {
00392         fprintf(stderr, "%lu", (ulong) val);
00393       }
00394       break;
00395 
00396     case 3:
00397       val = mach_read_from_3(data);
00398 
00399       if (!(prtype & DATA_UNSIGNED)) {
00400         val &= ~0x800000;
00401         fprintf(stderr, "%ld", (long) val);
00402       } else {
00403         fprintf(stderr, "%lu", (ulong) val);
00404       }
00405       break;
00406 
00407     case 4:
00408       val = mach_read_from_4(data);
00409 
00410       if (!(prtype & DATA_UNSIGNED)) {
00411         val &= ~UNSIGNED_MASK;
00412         fprintf(stderr, "%ld", (long) val);
00413       } else {
00414         fprintf(stderr, "%lu", (ulong) val);
00415       }
00416       break;
00417 
00418     case 6:
00419       id = mach_read_from_6(data);
00420       fprintf(stderr, "%llu", (ullint) id);
00421       break;
00422 
00423     case 7:
00424       id = mach_read_from_7(data);
00425       fprintf(stderr, "%llu", (ullint) id);
00426       break;
00427     case 8:
00428       id = mach_read_from_8(data);
00429       fprintf(stderr, "%llu", (ullint) id);
00430       break;
00431     default:
00432       goto print_hex;
00433     }
00434     break;
00435 
00436   case DATA_SYS:
00437     switch (prtype & DATA_SYS_PRTYPE_MASK) {
00438     case DATA_TRX_ID:
00439       id = mach_read_from_6(data);
00440 
00441       fprintf(stderr, "trx_id " TRX_ID_FMT, id);
00442       break;
00443 
00444     case DATA_ROLL_PTR:
00445       id = mach_read_from_7(data);
00446 
00447       fprintf(stderr, "roll_ptr " TRX_ID_FMT, id);
00448       break;
00449 
00450     case DATA_ROW_ID:
00451       id = mach_read_from_6(data);
00452 
00453       fprintf(stderr, "row_id " TRX_ID_FMT, id);
00454       break;
00455 
00456     default:
00457       id = mach_ull_read_compressed(data);
00458 
00459       fprintf(stderr, "mix_id " TRX_ID_FMT, id);
00460     }
00461     break;
00462 
00463   case DATA_CHAR:
00464   case DATA_VARCHAR:
00465     print_also_hex = FALSE;
00466 
00467     for (i = 0; i < len; i++) {
00468       int c = *data++;
00469 
00470       if (!isprint(c)) {
00471         print_also_hex = TRUE;
00472 
00473         fprintf(stderr, "\\x%02x", (unsigned char) c);
00474       } else {
00475         putc(c, stderr);
00476       }
00477     }
00478 
00479     if (dfield_is_ext(dfield)) {
00480       fputs("(external)", stderr);
00481     }
00482 
00483     if (!print_also_hex) {
00484       break;
00485     }
00486 
00487     data = static_cast<const byte *>(dfield_get_data(dfield));
00488     /* fall through */
00489 
00490   case DATA_BINARY:
00491   default:
00492 print_hex:
00493     fputs(" Hex: ",stderr);
00494 
00495     for (i = 0; i < len; i++) {
00496       fprintf(stderr, "%02lx", (ulint) *data++);
00497     }
00498 
00499     if (dfield_is_ext(dfield)) {
00500       fputs("(external)", stderr);
00501     }
00502   }
00503 }
00504 
00505 /*************************************************************/
00507 static
00508 void
00509 dfield_print_raw(
00510 /*=============*/
00511   FILE*   f,    
00512   const dfield_t* dfield)   
00513 {
00514   ulint len = dfield_get_len(dfield);
00515   if (!dfield_is_null(dfield)) {
00516     ulint print_len = ut_min(len, 1000);
00517     ut_print_buf(f, dfield_get_data(dfield), print_len);
00518     if (len != print_len) {
00519       fprintf(f, "(total %lu bytes%s)",
00520         (ulong) len,
00521         dfield_is_ext(dfield) ? ", external" : "");
00522     }
00523   } else {
00524     fputs(" SQL NULL", f);
00525   }
00526 }
00527 
00528 /**********************************************************/
00530 UNIV_INTERN
00531 void
00532 dtuple_print(
00533 /*=========*/
00534   FILE*   f,  
00535   const dtuple_t* tuple)  
00536 {
00537   ulint   n_fields;
00538   ulint   i;
00539 
00540   n_fields = dtuple_get_n_fields(tuple);
00541 
00542   fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
00543 
00544   for (i = 0; i < n_fields; i++) {
00545     fprintf(f, " %lu:", (ulong) i);
00546 
00547     dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
00548 
00549     putc(';', f);
00550     putc('\n', f);
00551   }
00552 
00553   ut_ad(dtuple_validate(tuple));
00554 }
00555 
00556 /**************************************************************/
00564 UNIV_INTERN
00565 big_rec_t*
00566 dtuple_convert_big_rec(
00567 /*===================*/
00568   dict_index_t* index,  
00569   dtuple_t* entry,  
00570   ulint*    n_ext)  
00572 {
00573   mem_heap_t* heap;
00574   big_rec_t*  vector;
00575   dfield_t* dfield;
00576   dict_field_t* ifield;
00577   ulint   size;
00578   ulint   n_fields;
00579   ulint   local_len;
00580   ulint   local_prefix_len;
00581 
00582   if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
00583     return(NULL);
00584   }
00585 
00586   if (dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP) {
00587     /* up to MySQL 5.1: store a 768-byte prefix locally */
00588     local_len = BTR_EXTERN_FIELD_REF_SIZE + DICT_MAX_INDEX_COL_LEN;
00589   } else {
00590     /* new-format table: do not store any BLOB prefix locally */
00591     local_len = BTR_EXTERN_FIELD_REF_SIZE;
00592   }
00593 
00594   ut_a(dtuple_check_typed_no_assert(entry));
00595 
00596   size = rec_get_converted_size(index, entry, *n_ext);
00597 
00598   if (UNIV_UNLIKELY(size > 1000000000)) {
00599     fprintf(stderr,
00600       "InnoDB: Warning: tuple size very big: %lu\n",
00601       (ulong) size);
00602     fputs("InnoDB: Tuple contents: ", stderr);
00603     dtuple_print(stderr, entry);
00604     putc('\n', stderr);
00605   }
00606 
00607   heap = mem_heap_create(size + dtuple_get_n_fields(entry)
00608              * sizeof(big_rec_field_t) + 1000);
00609 
00610   vector = static_cast<big_rec_t *>(mem_heap_alloc(heap, sizeof(big_rec_t)));
00611 
00612   vector->heap = heap;
00613   vector->fields = static_cast<big_rec_field_t *>(mem_heap_alloc(heap, dtuple_get_n_fields(entry)
00614           * sizeof(big_rec_field_t)));
00615 
00616   /* Decide which fields to shorten: the algorithm is to look for
00617   a variable-length field that yields the biggest savings when
00618   stored externally */
00619 
00620   n_fields = 0;
00621 
00622   while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry,
00623                    *n_ext),
00624               dict_table_is_comp(index->table),
00625               dict_index_get_n_fields(index),
00626               dict_table_zip_size(index->table))) {
00627     ulint     i;
00628     ulint     longest   = 0;
00629     ulint     longest_i = ULINT_MAX;
00630     byte*     data;
00631     big_rec_field_t*  b;
00632 
00633     for (i = dict_index_get_n_unique_in_tree(index);
00634          i < dtuple_get_n_fields(entry); i++) {
00635       ulint savings;
00636 
00637       dfield = dtuple_get_nth_field(entry, i);
00638       ifield = dict_index_get_nth_field(index, i);
00639 
00640       /* Skip fixed-length, NULL, externally stored,
00641       or short columns */
00642 
00643       if (ifield->fixed_len
00644           || dfield_is_null(dfield)
00645           || dfield_is_ext(dfield)
00646           || dfield_get_len(dfield) <= local_len
00647           || dfield_get_len(dfield)
00648           <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
00649         goto skip_field;
00650       }
00651 
00652       savings = dfield_get_len(dfield) - local_len;
00653 
00654       /* Check that there would be savings */
00655       if (longest >= savings) {
00656         goto skip_field;
00657       }
00658 
00659       /* In DYNAMIC and COMPRESSED format, store
00660       locally any non-BLOB columns whose maximum
00661       length does not exceed 256 bytes.  This is
00662       because there is no room for the "external
00663       storage" flag when the maximum length is 255
00664       bytes or less. This restriction trivially
00665       holds in REDUNDANT and COMPACT format, because
00666       there we always store locally columns whose
00667       length is up to local_len == 788 bytes.
00668       @see rec_init_offsets_comp_ordinary */
00669       if (ifield->col->mtype != DATA_BLOB
00670           && ifield->col->len < 256) {
00671         goto skip_field;
00672       }
00673 
00674       /* In DYNAMIC and COMPRESSED format, store
00675       locally any non-BLOB columns whose maximum
00676       length does not exceed 256 bytes.  This is
00677       because there is no room for the "external
00678       storage" flag when the maximum length is 255
00679       bytes or less. This restriction trivially
00680       holds in REDUNDANT and COMPACT format, because
00681       there we always store locally columns whose
00682       length is up to local_len == 788 bytes.
00683       @see rec_init_offsets_comp_ordinary */
00684       if (ifield->col->mtype != DATA_BLOB
00685           && ifield->col->len < 256) {
00686         goto skip_field;
00687       }
00688 
00689       /* In DYNAMIC and COMPRESSED format, store
00690       locally any non-BLOB columns whose maximum
00691       length does not exceed 256 bytes.  This is
00692       because there is no room for the "external
00693       storage" flag when the maximum length is 255
00694       bytes or less. This restriction trivially
00695       holds in REDUNDANT and COMPACT format, because
00696       there we always store locally columns whose
00697       length is up to local_len == 788 bytes.
00698       @see rec_init_offsets_comp_ordinary */
00699       if (ifield->col->mtype != DATA_BLOB
00700           && ifield->col->len < 256) {
00701         goto skip_field;
00702       }
00703 
00704       longest_i = i;
00705       longest = savings;
00706 
00707 skip_field:
00708       continue;
00709     }
00710 
00711     if (!longest) {
00712       /* Cannot shorten more */
00713 
00714       mem_heap_free(heap);
00715 
00716       return(NULL);
00717     }
00718 
00719     /* Move data from field longest_i to big rec vector.
00720 
00721     We store the first bytes locally to the record. Then
00722     we can calculate all ordering fields in all indexes
00723     from locally stored data. */
00724 
00725     dfield = dtuple_get_nth_field(entry, longest_i);
00726     ifield = dict_index_get_nth_field(index, longest_i);
00727     local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE;
00728 
00729     b = &vector->fields[n_fields];
00730     b->field_no = longest_i;
00731     b->len = dfield_get_len(dfield) - local_prefix_len;
00732     b->data = (char*) dfield_get_data(dfield) + local_prefix_len;
00733 
00734     /* Allocate the locally stored part of the column. */
00735     data = static_cast<unsigned char *>(mem_heap_alloc(heap, local_len));
00736 
00737     /* Copy the local prefix. */
00738     memcpy(data, dfield_get_data(dfield), local_prefix_len);
00739     /* Clear the extern field reference (BLOB pointer). */
00740     memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE);
00741 #if 0
00742     /* The following would fail the Valgrind checks in
00743     page_cur_insert_rec_low() and page_cur_insert_rec_zip().
00744     The BLOB pointers in the record will be initialized after
00745     the record and the BLOBs have been written. */
00746     UNIV_MEM_ALLOC(data + local_prefix_len,
00747              BTR_EXTERN_FIELD_REF_SIZE);
00748 #endif
00749 
00750     dfield_set_data(dfield, data, local_len);
00751     dfield_set_ext(dfield);
00752 
00753     n_fields++;
00754     (*n_ext)++;
00755     ut_ad(n_fields < dtuple_get_n_fields(entry));
00756   }
00757 
00758   vector->n_fields = n_fields;
00759   return(vector);
00760 }
00761 
00762 /**************************************************************/
00766 UNIV_INTERN
00767 void
00768 dtuple_convert_back_big_rec(
00769 /*========================*/
00770   dict_index_t* /*index __attribute__((unused))*/,  
00771   dtuple_t* entry,  
00772   big_rec_t*  vector) 
00774 {
00775   big_rec_field_t*    b = vector->fields;
00776   const big_rec_field_t* const  end = b + vector->n_fields;
00777 
00778   for (; b < end; b++) {
00779     dfield_t* dfield;
00780     ulint   local_len;
00781 
00782     dfield = dtuple_get_nth_field(entry, b->field_no);
00783     local_len = dfield_get_len(dfield);
00784 
00785     ut_ad(dfield_is_ext(dfield));
00786     ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
00787 
00788     local_len -= BTR_EXTERN_FIELD_REF_SIZE;
00789 
00790     ut_ad(local_len <= DICT_MAX_INDEX_COL_LEN);
00791 
00792     dfield_set_data(dfield,
00793         (char*) b->data - local_len,
00794         b->len + local_len);
00795   }
00796 
00797   mem_heap_free(vector->heap);
00798 }
00799 #endif /* !UNIV_HOTBACKUP */