Drizzled Public API Documentation

row0row.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1996, 2010, 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 "row0row.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "row0row.ic"
00030 #endif
00031 
00032 #include "data0type.h"
00033 #include "dict0dict.h"
00034 #include "btr0btr.h"
00035 #include "ha_prototypes.h"
00036 #include "mach0data.h"
00037 #include "trx0rseg.h"
00038 #include "trx0trx.h"
00039 #include "trx0roll.h"
00040 #include "trx0undo.h"
00041 #include "trx0purge.h"
00042 #include "trx0rec.h"
00043 #include "que0que.h"
00044 #include "row0ext.h"
00045 #include "row0upd.h"
00046 #include "rem0cmp.h"
00047 #include "read0read.h"
00048 #include "ut0mem.h"
00049 
00050 /*********************************************************************/
00054 UNIV_INTERN
00055 ulint
00056 row_get_trx_id_offset(
00057 /*==================*/
00058   const rec_t*  /*rec __attribute__((unused))*/,
00060   dict_index_t* index,  
00061   const ulint*  offsets)
00062 {
00063   ulint pos;
00064   ulint offset;
00065   ulint len;
00066 
00067   ut_ad(dict_index_is_clust(index));
00068   ut_ad(rec_offs_validate(rec, index, offsets));
00069 
00070   pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
00071 
00072   offset = rec_get_nth_field_offs(offsets, pos, &len);
00073 
00074   ut_ad(len == DATA_TRX_ID_LEN);
00075 
00076   return(offset);
00077 }
00078 
00079 /*****************************************************************/
00085 UNIV_INTERN
00086 dtuple_t*
00087 row_build_index_entry(
00088 /*==================*/
00089   const dtuple_t* row,  
00091   row_ext_t*  ext,  
00093   dict_index_t* index,  
00094   mem_heap_t* heap) 
00096 {
00097   dtuple_t* entry;
00098   ulint   entry_len;
00099   ulint   i;
00100 
00101   ut_ad(row && index && heap);
00102   ut_ad(dtuple_check_typed(row));
00103 
00104   entry_len = dict_index_get_n_fields(index);
00105   entry = dtuple_create(heap, entry_len);
00106 
00107   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
00108     dtuple_set_n_fields_cmp(entry, entry_len);
00109     /* There may only be externally stored columns
00110     in a clustered index B-tree of a user table. */
00111     ut_a(!ext);
00112   } else {
00113     dtuple_set_n_fields_cmp(
00114       entry, dict_index_get_n_unique_in_tree(index));
00115   }
00116 
00117   for (i = 0; i < entry_len; i++) {
00118     const dict_field_t* ind_field
00119       = dict_index_get_nth_field(index, i);
00120     const dict_col_t* col
00121       = ind_field->col;
00122     ulint     col_no
00123       = dict_col_get_no(col);
00124     dfield_t*   dfield
00125       = dtuple_get_nth_field(entry, i);
00126     const dfield_t*   dfield2
00127       = dtuple_get_nth_field(row, col_no);
00128     ulint     len
00129       = dfield_get_len(dfield2);
00130 
00131     dfield_copy(dfield, dfield2);
00132 
00133     if (dfield_is_null(dfield) || ind_field->prefix_len == 0) {
00134       continue;
00135     }
00136 
00137     /* If a column prefix index, take only the prefix.
00138     Prefix-indexed columns may be externally stored. */
00139     ut_ad(col->ord_part);
00140 
00141     if (UNIV_LIKELY_NULL(ext)) {
00142       /* See if the column is stored externally. */
00143       const byte* buf = row_ext_lookup(ext, col_no,
00144                    &len);
00145       if (UNIV_LIKELY_NULL(buf)) {
00146         if (UNIV_UNLIKELY(buf == field_ref_zero)) {
00147           return(NULL);
00148         }
00149         dfield_set_data(dfield, buf, len);
00150       }
00151     } else if (dfield_is_ext(dfield)) {
00152       ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
00153       len -= BTR_EXTERN_FIELD_REF_SIZE;
00154       ut_a(ind_field->prefix_len <= len
00155            || dict_index_is_clust(index));
00156     }
00157 
00158     len = dtype_get_at_most_n_mbchars(
00159       col->prtype, col->mbminmaxlen,
00160       ind_field->prefix_len, len, static_cast<const char *>(dfield_get_data(dfield)));
00161     dfield_set_len(dfield, len);
00162   }
00163 
00164   ut_ad(dtuple_check_typed(entry));
00165 
00166   return(entry);
00167 }
00168 
00169 /*******************************************************************/
00173 UNIV_INTERN
00174 dtuple_t*
00175 row_build(
00176 /*======*/
00177   ulint     type, 
00184   const dict_index_t* index,  
00185   const rec_t*    rec,  
00194   const ulint*    offsets,
00197   const dict_table_t* col_table,
00204   row_ext_t**   ext,  
00207   mem_heap_t*   heap) 
00209 {
00210   dtuple_t*   row;
00211   const dict_table_t* table;
00212   ulint     n_fields;
00213   ulint     n_ext_cols;
00214   ulint*      ext_cols  = NULL; /* remove warning */
00215   ulint     len;
00216   ulint     row_len;
00217   byte*     buf;
00218   ulint     i;
00219   ulint     j;
00220   mem_heap_t*   tmp_heap  = NULL;
00221   ulint     offsets_[REC_OFFS_NORMAL_SIZE];
00222   rec_offs_init(offsets_);
00223 
00224   ut_ad(index && rec && heap);
00225   ut_ad(dict_index_is_clust(index));
00226 
00227   if (!offsets) {
00228     offsets = rec_get_offsets(rec, index, offsets_,
00229             ULINT_UNDEFINED, &tmp_heap);
00230   } else {
00231     ut_ad(rec_offs_validate(rec, index, offsets));
00232   }
00233 
00234   if (type != ROW_COPY_POINTERS) {
00235     /* Take a copy of rec to heap */
00236     buf = static_cast<byte *>(mem_heap_alloc(heap, rec_offs_size(offsets)));
00237     rec = rec_copy(buf, rec, offsets);
00238     /* Avoid a debug assertion in rec_offs_validate(). */
00239     rec_offs_make_valid(rec, index, (ulint*) offsets);
00240   }
00241 
00242   table = index->table;
00243   row_len = dict_table_get_n_cols(table);
00244 
00245   row = dtuple_create(heap, row_len);
00246 
00247   dict_table_copy_types(row, table);
00248 
00249   dtuple_set_info_bits(row, rec_get_info_bits(
00250              rec, dict_table_is_comp(table)));
00251 
00252   n_fields = rec_offs_n_fields(offsets);
00253   n_ext_cols = rec_offs_n_extern(offsets);
00254   if (n_ext_cols) {
00255     ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols));
00256   }
00257 
00258   for (i = j = 0; i < n_fields; i++) {
00259     dict_field_t*   ind_field
00260       = dict_index_get_nth_field(index, i);
00261     const dict_col_t* col
00262       = dict_field_get_col(ind_field);
00263     ulint     col_no
00264       = dict_col_get_no(col);
00265     dfield_t*   dfield
00266       = dtuple_get_nth_field(row, col_no);
00267 
00268     if (ind_field->prefix_len == 0) {
00269 
00270       const byte* field = rec_get_nth_field(
00271         rec, offsets, i, &len);
00272 
00273       dfield_set_data(dfield, field, len);
00274     }
00275 
00276     if (rec_offs_nth_extern(offsets, i)) {
00277       dfield_set_ext(dfield);
00278 
00279       if (UNIV_LIKELY_NULL(col_table)) {
00280         ut_a(col_no
00281              < dict_table_get_n_cols(col_table));
00282         col = dict_table_get_nth_col(
00283           col_table, col_no);
00284       }
00285 
00286       if (col->ord_part) {
00287         /* We will have to fetch prefixes of
00288         externally stored columns that are
00289         referenced by column prefixes. */
00290         ext_cols[j++] = col_no;
00291       }
00292     }
00293   }
00294 
00295   ut_ad(dtuple_check_typed(row));
00296 
00297   if (!ext) {
00298     /* REDUNDANT and COMPACT formats store a local
00299     768-byte prefix of each externally stored
00300     column. No cache is needed. */
00301     ut_ad(dict_table_get_format(index->table)
00302           < DICT_TF_FORMAT_ZIP);
00303   } else if (j) {
00304     *ext = row_ext_create(j, ext_cols, row,
00305               dict_table_zip_size(index->table),
00306               heap);
00307   } else {
00308     *ext = NULL;
00309   }
00310 
00311   if (tmp_heap) {
00312     mem_heap_free(tmp_heap);
00313   }
00314 
00315   return(row);
00316 }
00317 
00318 /*******************************************************************/
00322 UNIV_INTERN
00323 dtuple_t*
00324 row_rec_to_index_entry_low(
00325 /*=======================*/
00326   const rec_t*    rec,  
00327   const dict_index_t* index,  
00328   const ulint*    offsets,
00329   ulint*      n_ext,  
00331   mem_heap_t*   heap) 
00333 {
00334   dtuple_t* entry;
00335   dfield_t* dfield;
00336   ulint   i;
00337   const byte* field;
00338   ulint   len;
00339   ulint   rec_len;
00340 
00341   ut_ad(rec && heap && index);
00342   /* Because this function may be invoked by row0merge.c
00343   on a record whose header is in different format, the check
00344   rec_offs_validate(rec, index, offsets) must be avoided here. */
00345   ut_ad(n_ext);
00346   *n_ext = 0;
00347 
00348   rec_len = rec_offs_n_fields(offsets);
00349 
00350   entry = dtuple_create(heap, rec_len);
00351 
00352   dtuple_set_n_fields_cmp(entry,
00353         dict_index_get_n_unique_in_tree(index));
00354   ut_ad(rec_len == dict_index_get_n_fields(index));
00355 
00356   dict_index_copy_types(entry, index, rec_len);
00357 
00358   for (i = 0; i < rec_len; i++) {
00359 
00360     dfield = dtuple_get_nth_field(entry, i);
00361     field = rec_get_nth_field(rec, offsets, i, &len);
00362 
00363     dfield_set_data(dfield, field, len);
00364 
00365     if (rec_offs_nth_extern(offsets, i)) {
00366       dfield_set_ext(dfield);
00367       (*n_ext)++;
00368     }
00369   }
00370 
00371   ut_ad(dtuple_check_typed(entry));
00372 
00373   return(entry);
00374 }
00375 
00376 /*******************************************************************/
00380 UNIV_INTERN
00381 dtuple_t*
00382 row_rec_to_index_entry(
00383 /*===================*/
00384   ulint     type, 
00390   const rec_t*    rec,  
00399   const dict_index_t* index,  
00400   ulint*      offsets,
00401   ulint*      n_ext,  
00403   mem_heap_t*   heap) 
00405 {
00406   dtuple_t* entry;
00407   byte*   buf;
00408 
00409   ut_ad(rec && heap && index);
00410   ut_ad(rec_offs_validate(rec, index, offsets));
00411 
00412   if (type == ROW_COPY_DATA) {
00413     /* Take a copy of rec to heap */
00414     buf = static_cast<byte *>(mem_heap_alloc(heap, rec_offs_size(offsets)));
00415     rec = rec_copy(buf, rec, offsets);
00416     /* Avoid a debug assertion in rec_offs_validate(). */
00417     rec_offs_make_valid(rec, index, offsets);
00418   }
00419 
00420   entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
00421 
00422   dtuple_set_info_bits(entry,
00423            rec_get_info_bits(rec, rec_offs_comp(offsets)));
00424 
00425   return(entry);
00426 }
00427 
00428 /*******************************************************************/
00432 UNIV_INTERN
00433 dtuple_t*
00434 row_build_row_ref(
00435 /*==============*/
00436   ulint   type, 
00440   dict_index_t* index,  
00441   const rec_t*  rec,  
00448   mem_heap_t* heap) 
00450 {
00451   dict_table_t* table;
00452   dict_index_t* clust_index;
00453   dfield_t* dfield;
00454   dtuple_t* ref;
00455   const byte* field;
00456   ulint   len;
00457   ulint   ref_len;
00458   ulint   pos;
00459   byte*   buf;
00460   ulint   clust_col_prefix_len;
00461   ulint   i;
00462   mem_heap_t* tmp_heap  = NULL;
00463   ulint   offsets_[REC_OFFS_NORMAL_SIZE];
00464   ulint*    offsets   = offsets_;
00465   rec_offs_init(offsets_);
00466 
00467   ut_ad(index && rec && heap);
00468   ut_ad(!dict_index_is_clust(index));
00469 
00470   offsets = rec_get_offsets(rec, index, offsets,
00471           ULINT_UNDEFINED, &tmp_heap);
00472   /* Secondary indexes must not contain externally stored columns. */
00473   ut_ad(!rec_offs_any_extern(offsets));
00474 
00475   if (type == ROW_COPY_DATA) {
00476     /* Take a copy of rec to heap */
00477 
00478     buf = static_cast<byte *>(mem_heap_alloc(heap, rec_offs_size(offsets)));
00479 
00480     rec = rec_copy(buf, rec, offsets);
00481     /* Avoid a debug assertion in rec_offs_validate(). */
00482     rec_offs_make_valid(rec, index, offsets);
00483   }
00484 
00485   table = index->table;
00486 
00487   clust_index = dict_table_get_first_index(table);
00488 
00489   ref_len = dict_index_get_n_unique(clust_index);
00490 
00491   ref = dtuple_create(heap, ref_len);
00492 
00493   dict_index_copy_types(ref, clust_index, ref_len);
00494 
00495   for (i = 0; i < ref_len; i++) {
00496     dfield = dtuple_get_nth_field(ref, i);
00497 
00498     pos = dict_index_get_nth_field_pos(index, clust_index, i);
00499 
00500     ut_a(pos != ULINT_UNDEFINED);
00501 
00502     field = rec_get_nth_field(rec, offsets, pos, &len);
00503 
00504     dfield_set_data(dfield, field, len);
00505 
00506     /* If the primary key contains a column prefix, then the
00507     secondary index may contain a longer prefix of the same
00508     column, or the full column, and we must adjust the length
00509     accordingly. */
00510 
00511     clust_col_prefix_len = dict_index_get_nth_field(
00512       clust_index, i)->prefix_len;
00513 
00514     if (clust_col_prefix_len > 0) {
00515       if (len != UNIV_SQL_NULL) {
00516 
00517         const dtype_t*  dtype
00518           = dfield_get_type(dfield);
00519 
00520         dfield_set_len(dfield,
00521                  dtype_get_at_most_n_mbchars(
00522                    dtype->prtype,
00523                    dtype->mbminmaxlen,
00524                    clust_col_prefix_len,
00525                    len, (char*) field));
00526       }
00527     }
00528   }
00529 
00530   ut_ad(dtuple_check_typed(ref));
00531   if (tmp_heap) {
00532     mem_heap_free(tmp_heap);
00533   }
00534 
00535   return(ref);
00536 }
00537 
00538 /*******************************************************************/
00541 UNIV_INTERN
00542 void
00543 row_build_row_ref_in_tuple(
00544 /*=======================*/
00545   dtuple_t*   ref,  
00547   const rec_t*    rec,  
00555   const dict_index_t* index,  
00556   ulint*      offsets,
00558   trx_t*      trx)  
00559 {
00560   const dict_index_t* clust_index;
00561   dfield_t*   dfield;
00562   const byte*   field;
00563   ulint     len;
00564   ulint     ref_len;
00565   ulint     pos;
00566   ulint     clust_col_prefix_len;
00567   ulint     i;
00568   mem_heap_t*   heap    = NULL;
00569   ulint     offsets_[REC_OFFS_NORMAL_SIZE];
00570   rec_offs_init(offsets_);
00571 
00572   ut_a(ref);
00573   ut_a(index);
00574   ut_a(rec);
00575   ut_ad(!dict_index_is_clust(index));
00576 
00577   if (UNIV_UNLIKELY(!index->table)) {
00578     fputs("InnoDB: table ", stderr);
00579 notfound:
00580     ut_print_name(stderr, trx, TRUE, index->table_name);
00581     fputs(" for index ", stderr);
00582     ut_print_name(stderr, trx, FALSE, index->name);
00583     fputs(" not found\n", stderr);
00584     ut_error;
00585   }
00586 
00587   clust_index = dict_table_get_first_index(index->table);
00588 
00589   if (UNIV_UNLIKELY(!clust_index)) {
00590     fputs("InnoDB: clust index for table ", stderr);
00591     goto notfound;
00592   }
00593 
00594   if (!offsets) {
00595     offsets = rec_get_offsets(rec, index, offsets_,
00596             ULINT_UNDEFINED, &heap);
00597   } else {
00598     ut_ad(rec_offs_validate(rec, index, offsets));
00599   }
00600 
00601   /* Secondary indexes must not contain externally stored columns. */
00602   ut_ad(!rec_offs_any_extern(offsets));
00603   ref_len = dict_index_get_n_unique(clust_index);
00604 
00605   ut_ad(ref_len == dtuple_get_n_fields(ref));
00606 
00607   dict_index_copy_types(ref, clust_index, ref_len);
00608 
00609   for (i = 0; i < ref_len; i++) {
00610     dfield = dtuple_get_nth_field(ref, i);
00611 
00612     pos = dict_index_get_nth_field_pos(index, clust_index, i);
00613 
00614     ut_a(pos != ULINT_UNDEFINED);
00615 
00616     field = rec_get_nth_field(rec, offsets, pos, &len);
00617 
00618     dfield_set_data(dfield, field, len);
00619 
00620     /* If the primary key contains a column prefix, then the
00621     secondary index may contain a longer prefix of the same
00622     column, or the full column, and we must adjust the length
00623     accordingly. */
00624 
00625     clust_col_prefix_len = dict_index_get_nth_field(
00626       clust_index, i)->prefix_len;
00627 
00628     if (clust_col_prefix_len > 0) {
00629       if (len != UNIV_SQL_NULL) {
00630 
00631         const dtype_t*  dtype
00632           = dfield_get_type(dfield);
00633 
00634         dfield_set_len(dfield,
00635                  dtype_get_at_most_n_mbchars(
00636                    dtype->prtype,
00637                    dtype->mbminmaxlen,
00638                    clust_col_prefix_len,
00639                    len, (char*) field));
00640       }
00641     }
00642   }
00643 
00644   ut_ad(dtuple_check_typed(ref));
00645   if (UNIV_LIKELY_NULL(heap)) {
00646     mem_heap_free(heap);
00647   }
00648 }
00649 
00650 /***************************************************************/
00653 UNIV_INTERN
00654 ibool
00655 row_search_on_row_ref(
00656 /*==================*/
00657   btr_pcur_t*   pcur, 
00659   ulint     mode, 
00660   const dict_table_t* table,  
00661   const dtuple_t*   ref,  
00662   mtr_t*      mtr)  
00663 {
00664   ulint   low_match;
00665   rec_t*    rec;
00666   dict_index_t* index;
00667 
00668   ut_ad(dtuple_check_typed(ref));
00669 
00670   index = dict_table_get_first_index(table);
00671 
00672   ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
00673 
00674   btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
00675 
00676   low_match = btr_pcur_get_low_match(pcur);
00677 
00678   rec = btr_pcur_get_rec(pcur);
00679 
00680   if (page_rec_is_infimum(rec)) {
00681 
00682     return(FALSE);
00683   }
00684 
00685   if (low_match != dtuple_get_n_fields(ref)) {
00686 
00687     return(FALSE);
00688   }
00689 
00690   return(TRUE);
00691 }
00692 
00693 /*********************************************************************/
00697 UNIV_INTERN
00698 rec_t*
00699 row_get_clust_rec(
00700 /*==============*/
00701   ulint   mode, 
00702   const rec_t*  rec,  
00703   dict_index_t* index,  
00704   dict_index_t**  clust_index,
00705   mtr_t*    mtr)  
00706 {
00707   mem_heap_t* heap;
00708   dtuple_t* ref;
00709   dict_table_t* table;
00710   btr_pcur_t  pcur;
00711   ibool   found;
00712   rec_t*    clust_rec;
00713 
00714   ut_ad(!dict_index_is_clust(index));
00715 
00716   table = index->table;
00717 
00718   heap = mem_heap_create(256);
00719 
00720   ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
00721 
00722   found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
00723 
00724   clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
00725 
00726   mem_heap_free(heap);
00727 
00728   btr_pcur_close(&pcur);
00729 
00730   *clust_index = dict_table_get_first_index(table);
00731 
00732   return(clust_rec);
00733 }
00734 
00735 /***************************************************************/
00738 UNIV_INTERN
00739 enum row_search_result
00740 row_search_index_entry(
00741 /*===================*/
00742   dict_index_t* index,  
00743   const dtuple_t* entry,  
00744   ulint   mode, 
00745   btr_pcur_t* pcur, 
00747   mtr_t*    mtr)  
00748 {
00749   ulint n_fields;
00750   ulint low_match;
00751   rec_t*  rec;
00752 
00753   ut_ad(dtuple_check_typed(entry));
00754 
00755   btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
00756 
00757   switch (btr_pcur_get_btr_cur(pcur)->flag) {
00758   case BTR_CUR_DELETE_REF:
00759     ut_a(mode & BTR_DELETE);
00760     return(ROW_NOT_DELETED_REF);
00761 
00762   case BTR_CUR_DEL_MARK_IBUF:
00763   case BTR_CUR_DELETE_IBUF:
00764   case BTR_CUR_INSERT_TO_IBUF:
00765     return(ROW_BUFFERED);
00766 
00767   case BTR_CUR_HASH:
00768   case BTR_CUR_HASH_FAIL:
00769   case BTR_CUR_BINARY:
00770     break;
00771   }
00772 
00773   low_match = btr_pcur_get_low_match(pcur);
00774 
00775   rec = btr_pcur_get_rec(pcur);
00776 
00777   n_fields = dtuple_get_n_fields(entry);
00778 
00779   if (page_rec_is_infimum(rec)) {
00780 
00781     return(ROW_NOT_FOUND);
00782   } else if (low_match != n_fields) {
00783 
00784     return(ROW_NOT_FOUND);
00785   }
00786 
00787   return(ROW_FOUND);
00788 }
00789 
00790 #if !defined(BUILD_DRIZZLE)
00791 # include "my_sys.h"
00792 #endif
00793 
00794 
00795 /*******************************************************************/
00806 static
00807 ulint
00808 row_raw_format_int(
00809 /*===============*/
00810   const char* data,   
00811   ulint   data_len, 
00813   ulint   prtype,   
00814   char*   buf,    
00815   ulint   buf_size, 
00817   ibool*    format_in_hex)  
00819 {
00820   ulint ret;
00821 
00822   if (data_len <= sizeof(ullint)) {
00823 
00824     ullint    value;
00825     ibool   unsigned_type = prtype & DATA_UNSIGNED;
00826 
00827     value = mach_read_int_type((const byte*) data,
00828              data_len, unsigned_type);
00829 
00830     if (unsigned_type) {
00831 
00832       ret = ut_snprintf(buf, buf_size, "%llu",
00833             value) + 1;
00834     } else {
00835 
00836       ret = ut_snprintf(buf, buf_size, "%lld",
00837             (long long) value) + 1;
00838     }
00839 
00840   } else {
00841 
00842     *format_in_hex = TRUE;
00843     ret = 0;
00844   }
00845 
00846   return(ut_min(ret, buf_size));
00847 }
00848 
00849 /*******************************************************************/
00861 static
00862 ulint
00863 row_raw_format_str(
00864 /*===============*/
00865   const char* data,   
00866   ulint   data_len, 
00868   ulint   prtype,   
00869   char*   buf,    
00870   ulint   buf_size, 
00872   ibool*    format_in_hex)  
00874 {
00875   ulint charset_coll;
00876 
00877   if (buf_size == 0) {
00878 
00879     return(0);
00880   }
00881 
00882   /* we assume system_charset_info is UTF-8 */
00883 
00884   charset_coll = dtype_get_charset_coll(prtype);
00885 
00886   if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
00887 
00888     return(ut_str_sql_format(data, data_len, buf, buf_size));
00889   }
00890   /* else */
00891 
00892   if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
00893 
00894     *format_in_hex = TRUE;
00895     return(0);
00896   }
00897   /* else */
00898 
00899   return(innobase_raw_format(data, data_len, charset_coll,
00900             buf, buf_size));
00901 }
00902 
00903 /*******************************************************************/
00911 UNIV_INTERN
00912 ulint
00913 row_raw_format(
00914 /*===========*/
00915   const char*   data,   
00916   ulint     data_len, 
00918   const dict_field_t* dict_field, 
00919   char*     buf,    
00920   ulint     buf_size) 
00922 {
00923   ulint mtype;
00924   ulint prtype;
00925   ulint ret= 0;
00926   ibool format_in_hex;
00927 
00928   if (buf_size == 0) {
00929 
00930     return(ret);
00931   }
00932 
00933   if (data_len == UNIV_SQL_NULL) {
00934 
00935     ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
00936 
00937     return(ut_min(ret, buf_size));
00938   }
00939 
00940   mtype = dict_field->col->mtype;
00941   prtype = dict_field->col->prtype;
00942 
00943   format_in_hex = FALSE;
00944 
00945   switch (mtype) {
00946   case DATA_INT:
00947 
00948     ret = row_raw_format_int(data, data_len, prtype,
00949            buf, buf_size, &format_in_hex);
00950     if (format_in_hex) {
00951 
00952       goto format_in_hex;
00953     }
00954     break;
00955   case DATA_CHAR:
00956   case DATA_VARCHAR:
00957   case DATA_MYSQL:
00958   case DATA_VARMYSQL:
00959 
00960     ret = row_raw_format_str(data, data_len, prtype,
00961            buf, buf_size, &format_in_hex);
00962     if (format_in_hex) {
00963 
00964       goto format_in_hex;
00965     }
00966 
00967     break;
00968   /* XXX support more data types */
00969   default:
00970   format_in_hex:
00971 
00972     if (UNIV_LIKELY(buf_size > 2)) {
00973 
00974       memcpy(buf, "0x", 2);
00975       buf += 2;
00976       buf_size -= 2;
00977       ret = 2 + ut_raw_to_hex(data, data_len,
00978             buf, buf_size);
00979     } else {
00980 
00981       buf[0] = '\0';
00982       ret = 1;
00983     }
00984   }
00985 
00986   return(ret);
00987 }
00988 
00989 #ifdef UNIV_COMPILE_TEST_FUNCS
00990 
00991 #include "ut0dbg.h"
00992 
00993 void
00994 test_row_raw_format_int()
00995 {
00996   ulint ret;
00997   char  buf[128];
00998   ibool format_in_hex;
00999 
01000 #define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
01001           ret_expected, buf_expected, format_in_hex_expected)\
01002   do {\
01003     ibool ok = TRUE;\
01004     ulint i;\
01005     memset(buf, 'x', 10);\
01006     buf[10] = '\0';\
01007     format_in_hex = FALSE;\
01008     fprintf(stderr, "TESTING \"\\x");\
01009     for (i = 0; i < data_len; i++) {\
01010       fprintf(stderr, "%02hhX", data[i]);\
01011     }\
01012     fprintf(stderr, "\", %lu, %lu, %lu\n",\
01013                         (ulint) data_len, (ulint) prtype,\
01014       (ulint) buf_size);\
01015     ret = row_raw_format_int(data, data_len, prtype,\
01016            buf, buf_size, &format_in_hex);\
01017     if (ret != ret_expected) {\
01018       fprintf(stderr, "expected ret %lu, got %lu\n",\
01019         (ulint) ret_expected, ret);\
01020       ok = FALSE;\
01021                 }\
01022                 if (strcmp((char*) buf, buf_expected) != 0) {\
01023                         fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
01024                                 buf_expected, buf);\
01025                         ok = FALSE;\
01026                 }\
01027                 if (format_in_hex != format_in_hex_expected) {\
01028                         fprintf(stderr, "expected format_in_hex %d, got %d\n",\
01029                                 (int) format_in_hex_expected,\
01030         (int) format_in_hex);\
01031                         ok = FALSE;\
01032                 }\
01033                 if (ok) {\
01034                         fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
01035                                 (ulint) ret, buf, (int) format_in_hex);\
01036                 } else {\
01037                         return;\
01038                 }\
01039         } while (0)
01040 
01041 #if 1
01042   /* min values for signed 1-8 byte integers */
01043 
01044   CALL_AND_TEST("\x00", 1, 0,
01045           buf, sizeof(buf), 5, "-128", 0);
01046 
01047   CALL_AND_TEST("\x00\x00", 2, 0,
01048           buf, sizeof(buf), 7, "-32768", 0);
01049 
01050   CALL_AND_TEST("\x00\x00\x00", 3, 0,
01051           buf, sizeof(buf), 9, "-8388608", 0);
01052 
01053   CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
01054           buf, sizeof(buf), 12, "-2147483648", 0);
01055 
01056   CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
01057           buf, sizeof(buf), 14, "-549755813888", 0);
01058 
01059   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
01060           buf, sizeof(buf), 17, "-140737488355328", 0);
01061 
01062   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
01063           buf, sizeof(buf), 19, "-36028797018963968", 0);
01064 
01065   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
01066           buf, sizeof(buf), 21, "-9223372036854775808", 0);
01067 
01068   /* min values for unsigned 1-8 byte integers */
01069 
01070   CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
01071           buf, sizeof(buf), 2, "0", 0);
01072 
01073   CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
01074           buf, sizeof(buf), 2, "0", 0);
01075 
01076   CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
01077           buf, sizeof(buf), 2, "0", 0);
01078 
01079   CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
01080           buf, sizeof(buf), 2, "0", 0);
01081 
01082   CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
01083           buf, sizeof(buf), 2, "0", 0);
01084 
01085   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
01086           buf, sizeof(buf), 2, "0", 0);
01087 
01088   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
01089           buf, sizeof(buf), 2, "0", 0);
01090 
01091   CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
01092           buf, sizeof(buf), 2, "0", 0);
01093 
01094   /* max values for signed 1-8 byte integers */
01095 
01096   CALL_AND_TEST("\xFF", 1, 0,
01097           buf, sizeof(buf), 4, "127", 0);
01098 
01099   CALL_AND_TEST("\xFF\xFF", 2, 0,
01100           buf, sizeof(buf), 6, "32767", 0);
01101 
01102   CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
01103           buf, sizeof(buf), 8, "8388607", 0);
01104 
01105   CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
01106           buf, sizeof(buf), 11, "2147483647", 0);
01107 
01108   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
01109           buf, sizeof(buf), 13, "549755813887", 0);
01110 
01111   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
01112           buf, sizeof(buf), 16, "140737488355327", 0);
01113 
01114   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
01115           buf, sizeof(buf), 18, "36028797018963967", 0);
01116 
01117   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
01118           buf, sizeof(buf), 20, "9223372036854775807", 0);
01119 
01120   /* max values for unsigned 1-8 byte integers */
01121 
01122   CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
01123           buf, sizeof(buf), 4, "255", 0);
01124 
01125   CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
01126           buf, sizeof(buf), 6, "65535", 0);
01127 
01128   CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
01129           buf, sizeof(buf), 9, "16777215", 0);
01130 
01131   CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
01132           buf, sizeof(buf), 11, "4294967295", 0);
01133 
01134   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
01135           buf, sizeof(buf), 14, "1099511627775", 0);
01136 
01137   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
01138           buf, sizeof(buf), 16, "281474976710655", 0);
01139 
01140   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
01141           buf, sizeof(buf), 18, "72057594037927935", 0);
01142 
01143   CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
01144           buf, sizeof(buf), 21, "18446744073709551615", 0);
01145 
01146   /* some random values */
01147 
01148   CALL_AND_TEST("\x52", 1, 0,
01149           buf, sizeof(buf), 4, "-46", 0);
01150 
01151   CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
01152           buf, sizeof(buf), 3, "14", 0);
01153 
01154   CALL_AND_TEST("\x62\xCE", 2, 0,
01155           buf, sizeof(buf), 6, "-7474", 0);
01156 
01157   CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
01158           buf, sizeof(buf), 6, "10710", 0);
01159 
01160   CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
01161           buf, sizeof(buf), 5, "-112", 0);
01162 
01163   CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
01164           buf, sizeof(buf), 6, "41238", 0);
01165 
01166   CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
01167           buf, sizeof(buf), 3, "-9", 0);
01168 
01169   CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
01170           buf, sizeof(buf), 3, "92", 0);
01171 
01172   CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
01173           buf, sizeof(buf), 6, "-9117", 0);
01174 
01175   CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
01176           buf, sizeof(buf), 6, "91234", 0);
01177 #endif
01178 
01179   /* speed test */
01180 
01181   speedo_t  speedo;
01182   ulint   i;
01183 
01184   speedo_reset(&speedo);
01185 
01186   for (i = 0; i < 1000000; i++) {
01187     row_raw_format_int("\x23", 1,
01188            0, buf, sizeof(buf),
01189            &format_in_hex);
01190     row_raw_format_int("\x23", 1,
01191            DATA_UNSIGNED, buf, sizeof(buf),
01192            &format_in_hex);
01193 
01194     row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
01195            0, buf, sizeof(buf),
01196            &format_in_hex);
01197     row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
01198            DATA_UNSIGNED, buf, sizeof(buf),
01199            &format_in_hex);
01200   }
01201 
01202   speedo_show(&speedo);
01203 }
01204 
01205 #endif /* UNIV_COMPILE_TEST_FUNCS */