Drizzled Public API Documentation

blob.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 MySQL
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 
00022 #include <config.h>
00023 #include <drizzled/field/blob.h>
00024 #include <drizzled/table.h>
00025 #include <drizzled/session.h>
00026 #include <plugin/myisam/myisam.h>
00027 #include <drizzled/system_variables.h>
00028 
00029 #include <string>
00030 #include <algorithm>
00031 
00032 using namespace std;
00033 
00034 namespace drizzled {
00035 
00036 static uint32_t blob_pack_length_to_max_length(uint32_t arg)
00037 {
00038   return max(UINT32_MAX,
00039              (uint32_t)((INT64_C(1) << min(arg, 4U) * 8) - INT64_C(1)));
00040 }
00041 
00042 
00043 /****************************************************************************
00044 ** blob type
00045 ** A blob is saved as a length and a pointer. The length is stored in the
00046 ** packlength slot and is sizeof(uint32_t) (4 bytes)
00047 ****************************************************************************/
00048 
00049 Field_blob::Field_blob(unsigned char *ptr_arg,
00050                        unsigned char *null_ptr_arg,
00051                        unsigned char null_bit_arg,
00052                        const char *field_name_arg,
00053                        TableShare *share,
00054                        const charset_info_st * const cs)
00055   :Field_str(ptr_arg,
00056              blob_pack_length_to_max_length(sizeof(uint32_t)),
00057              null_ptr_arg,
00058              null_bit_arg,
00059              field_name_arg,
00060              cs)
00061 {
00062   flags|= BLOB_FLAG;
00063   share->blob_fields++;
00064   /* TODO: why do not fill table->getShare()->blob_field array here? */
00065 }
00066 
00067 void Field_blob::store_length(unsigned char *i_ptr,
00068                               uint32_t i_number,
00069                               bool low_byte_first)
00070 {
00071 #ifndef WORDS_BIGENDIAN
00072   (void)low_byte_first;
00073 #endif
00074 
00075 #ifdef WORDS_BIGENDIAN
00076   if (low_byte_first)
00077   {
00078     int4store(i_ptr,i_number);
00079   }
00080   else
00081 #endif
00082     longstore(i_ptr,i_number);
00083 }
00084 
00085 
00086 void Field_blob::store_length(unsigned char *i_ptr, uint32_t i_number)
00087 {
00088   store_length(i_ptr, i_number, getTable()->getShare()->db_low_byte_first);
00089 }
00090 
00091 
00092 uint32_t Field_blob::get_length(const unsigned char *pos,
00093                                 bool low_byte_first) const
00094 {
00095 #ifndef WORDS_BIGENDIAN
00096   (void)low_byte_first;
00097 #endif
00098   uint32_t tmp;
00099 #ifdef WORDS_BIGENDIAN
00100   if (low_byte_first)
00101     tmp=uint4korr(pos);
00102   else
00103 #endif
00104     longget(tmp,pos);
00105   return (uint32_t) tmp;
00106 }
00107 
00108 
00109 uint32_t Field_blob::get_packed_size(const unsigned char *ptr_arg,
00110                                 bool low_byte_first)
00111 {
00112   return sizeof(uint32_t) + get_length(ptr_arg, low_byte_first);
00113 }
00114 
00115 
00116 uint32_t Field_blob::get_length(uint32_t row_offset) const
00117 {
00118   return get_length(ptr+row_offset,
00119                     getTable()->getShare()->db_low_byte_first);
00120 }
00121 
00122 
00123 uint32_t Field_blob::get_length(const unsigned char *ptr_arg) const
00124 {
00125   return get_length(ptr_arg, getTable()->getShare()->db_low_byte_first);
00126 }
00127 
00128 
00138 void Field_blob::put_length(unsigned char *pos, uint32_t length)
00139 {
00140     int4store(pos, length);
00141 }
00142 
00143 
00144 int Field_blob::store(const char *from,uint32_t length, const charset_info_st * const cs)
00145 {
00146   uint32_t copy_length, new_length;
00147   const char *well_formed_error_pos;
00148   const char *cannot_convert_error_pos;
00149   const char *from_end_pos, *tmp;
00150   char buff[STRING_BUFFER_USUAL_SIZE];
00151   String tmpstr(buff,sizeof(buff), &my_charset_bin);
00152 
00153   ASSERT_COLUMN_MARKED_FOR_WRITE;
00154 
00155   if (!length)
00156   {
00157     memset(ptr, 0, Field_blob::pack_length());
00158     return 0;
00159   }
00160 
00161   if (from == value.ptr())
00162   {
00163     if (!String::needs_conversion(length, cs, field_charset))
00164     {
00165       Field_blob::store_length(length);
00166       memmove(ptr+sizeof(uint32_t), &from, sizeof(char*));
00167       return 0;
00168     }
00169     tmpstr.copy(from, length, cs);
00170     from= tmpstr.ptr();
00171   }
00172 
00173   new_length= min(max_data_length(), field_charset->mbmaxlen * length);
00174   value.alloc(new_length);
00175 
00176   /*
00177     "length" is OK as "nchars" argument to well_formed_copy_nchars as this
00178     is never used to limit the length of the data. The cut of long data
00179     is done with the new_length value.
00180   */
00181   copy_length= well_formed_copy_nchars(field_charset,
00182                                        (char*) value.ptr(), new_length,
00183                                        cs, from, length,
00184                                        length,
00185                                        &well_formed_error_pos,
00186                                        &cannot_convert_error_pos,
00187                                        &from_end_pos);
00188 
00189   Field_blob::store_length(copy_length);
00190   tmp= value.ptr();
00191   memmove(ptr+sizeof(uint32_t), &tmp, sizeof(char*));
00192 
00193   if (check_string_copy_error(this, well_formed_error_pos,
00194                               cannot_convert_error_pos, from + length, cs))
00195     return 2;
00196 
00197   return report_if_important_data(from_end_pos, from + length);
00198 }
00199 
00200 int Field_blob::store(double nr)
00201 {
00202   const charset_info_st * const cs=charset();
00203   ASSERT_COLUMN_MARKED_FOR_WRITE;
00204   value.set_real(nr, NOT_FIXED_DEC, cs);
00205   return Field_blob::store(value.ptr(),(uint32_t) value.length(), cs);
00206 }
00207 
00208 int Field_blob::store(int64_t nr, bool unsigned_val)
00209 {
00210   const charset_info_st * const cs=charset();
00211   ASSERT_COLUMN_MARKED_FOR_WRITE;
00212   value.set_int(nr, unsigned_val, cs);
00213   return Field_blob::store(value.ptr(), (uint32_t) value.length(), cs);
00214 }
00215 
00216 
00217 double Field_blob::val_real(void) const
00218 {
00219   int not_used;
00220   char *end_not_used, *blob;
00221   uint32_t length;
00222   const charset_info_st *cs;
00223 
00224   ASSERT_COLUMN_MARKED_FOR_READ;
00225 
00226   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00227   if (!blob)
00228     return 0.0;
00229   length= get_length(ptr);
00230   cs= charset();
00231   return my_strntod(cs, blob, length, &end_not_used, &not_used);
00232 }
00233 
00234 
00235 int64_t Field_blob::val_int(void) const
00236 {
00237   int not_used;
00238   char *blob;
00239 
00240   ASSERT_COLUMN_MARKED_FOR_READ;
00241 
00242   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00243   if (!blob)
00244     return 0;
00245   uint32_t length= get_length(ptr);
00246   return my_strntoll(charset(),blob,length,10,NULL,&not_used);
00247 }
00248 
00249 String *Field_blob::val_str(String *, String *val_ptr) const
00250 {
00251   char *blob;
00252 
00253   ASSERT_COLUMN_MARKED_FOR_READ;
00254 
00255   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00256   if (!blob)
00257     val_ptr->set("",0,charset()); // A bit safer than ->length(0)
00258   else
00259     val_ptr->set(blob,get_length(ptr),charset());
00260   return val_ptr;
00261 }
00262 
00263 
00264 type::Decimal *Field_blob::val_decimal(type::Decimal *decimal_value) const
00265 {
00266   const char *blob;
00267   size_t length;
00268 
00269   ASSERT_COLUMN_MARKED_FOR_READ;
00270 
00271   memcpy(&blob, ptr+sizeof(uint32_t), sizeof(const unsigned char*));
00272   if (!blob)
00273   {
00274     blob= "";
00275     length= 0;
00276   }
00277   else
00278   {
00279     length= get_length(ptr);
00280   }
00281 
00282   decimal_value->store(E_DEC_FATAL_ERROR, blob, length, charset());
00283 
00284   return decimal_value;
00285 }
00286 
00287 
00288 int Field_blob::cmp(const unsigned char *a,uint32_t a_length, const unsigned char *b,
00289         uint32_t b_length)
00290 {
00291   return field_charset->coll->strnncollsp(field_charset,
00292                                           a, a_length, b, b_length,
00293                                           0);
00294 }
00295 
00296 
00297 int Field_blob::cmp_max(const unsigned char *a_ptr, const unsigned char *b_ptr,
00298                         uint32_t max_length)
00299 {
00300   unsigned char *blob1,*blob2;
00301   memcpy(&blob1,a_ptr+sizeof(uint32_t),sizeof(char*));
00302   memcpy(&blob2,b_ptr+sizeof(uint32_t),sizeof(char*));
00303   uint32_t a_len= get_length(a_ptr), b_len= get_length(b_ptr);
00304   set_if_smaller(a_len, max_length);
00305   set_if_smaller(b_len, max_length);
00306   return Field_blob::cmp(blob1,a_len,blob2,b_len);
00307 }
00308 
00309 
00310 int Field_blob::cmp_binary(const unsigned char *a_ptr, const unsigned char *b_ptr,
00311                            uint32_t max_length)
00312 {
00313   char *a,*b;
00314   uint32_t diff;
00315   uint32_t a_length,b_length;
00316   memcpy(&a,a_ptr+sizeof(uint32_t),sizeof(char*));
00317   memcpy(&b,b_ptr+sizeof(uint32_t),sizeof(char*));
00318 
00319   a_length= get_length(a_ptr);
00320 
00321   if (a_length > max_length)
00322     a_length= max_length;
00323 
00324   b_length= get_length(b_ptr);
00325 
00326   if (b_length > max_length)
00327     b_length= max_length;
00328 
00329   diff= memcmp(a,b,min(a_length,b_length));
00330 
00331   return diff ? diff : (unsigned int) (a_length - b_length);
00332 }
00333 
00334 /* The following is used only when comparing a key */
00335 uint32_t Field_blob::get_key_image(unsigned char *buff, uint32_t length)
00336 {
00337   uint32_t blob_length= get_length(ptr);
00338   unsigned char *blob= get_ptr();
00339   uint32_t local_char_length= length / field_charset->mbmaxlen;
00340   local_char_length= my_charpos(field_charset, blob, blob + blob_length,
00341                           local_char_length);
00342   set_if_smaller(blob_length, local_char_length);
00343 
00344   if ((uint32_t) length > blob_length)
00345   {
00346     /*
00347       Must clear this as we do a memcmp in optimizer/range.cc to detect
00348       identical keys
00349     */
00350     memset(buff+HA_KEY_BLOB_LENGTH+blob_length, 0, (length-blob_length));
00351     length=(uint32_t) blob_length;
00352   }
00353   int2store(buff,length);
00354   memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
00355   return HA_KEY_BLOB_LENGTH+length;
00356 }
00357 
00358 uint32_t Field_blob::get_key_image(basic_string<unsigned char> &buff, uint32_t length)
00359 {
00360   uint32_t blob_length= get_length(ptr);
00361   unsigned char* blob= get_ptr();
00362   uint32_t local_char_length= length / field_charset->mbmaxlen;
00363   local_char_length= my_charpos(field_charset, blob, blob + blob_length,
00364                                 local_char_length);
00365   set_if_smaller(blob_length, local_char_length);
00366 
00367   unsigned char len_buff[HA_KEY_BLOB_LENGTH];
00368   int2store(len_buff,length);
00369   buff.append(len_buff);
00370   buff.append(blob, blob_length);
00371 
00372   if (length > blob_length)
00373   {
00374     /*
00375       Must clear this as we do a memcmp in optimizer/range.cc to detect
00376       identical keys
00377     */
00378 
00379     buff.append(length-blob_length, '0');
00380   }
00381   return HA_KEY_BLOB_LENGTH+length;
00382 }
00383 
00384 void Field_blob::set_key_image(const unsigned char *buff,uint32_t length)
00385 {
00386   length= uint2korr(buff);
00387   (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, field_charset);
00388 }
00389 
00390 int Field_blob::key_cmp(const unsigned char *key_ptr, uint32_t max_key_length)
00391 {
00392   unsigned char *blob1;
00393   uint32_t blob_length=get_length(ptr);
00394   memcpy(&blob1,ptr+sizeof(uint32_t),sizeof(char*));
00395   const charset_info_st * const cs= charset();
00396   uint32_t local_char_length= max_key_length / cs->mbmaxlen;
00397   local_char_length= my_charpos(cs, blob1, blob1+blob_length,
00398                                 local_char_length);
00399   set_if_smaller(blob_length, local_char_length);
00400   return Field_blob::cmp(blob1, blob_length,
00401        key_ptr+HA_KEY_BLOB_LENGTH,
00402        uint2korr(key_ptr));
00403 }
00404 
00405 int Field_blob::key_cmp(const unsigned char *a,const unsigned char *b)
00406 {
00407   return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
00408        b+HA_KEY_BLOB_LENGTH, uint2korr(b));
00409 }
00410 
00411 uint32_t Field_blob::sort_length() const
00412 {
00413   return (uint32_t) (getTable()->getSession()->variables.max_sort_length +
00414                      (field_charset == &my_charset_bin ? 0 : sizeof(uint32_t)));
00415 }
00416 
00417 void Field_blob::sort_string(unsigned char *to,uint32_t length)
00418 {
00419   unsigned char *blob;
00420   uint32_t blob_length=get_length();
00421 
00422   if (!blob_length)
00423     memset(to, 0, length);
00424   else
00425   {
00426     if (field_charset == &my_charset_bin)
00427     {
00428       unsigned char *pos;
00429 
00430       /*
00431         Store length of blob last in blob to shorter blobs before longer blobs
00432       */
00433       length-= sizeof(uint32_t); // size of stored blob length
00434       pos= to+length;
00435 
00436       mi_int4store(pos, blob_length);
00437     }
00438     memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00439 
00440     blob_length= field_charset->strnxfrm(to, length, blob, blob_length);
00441     assert(blob_length == length);
00442   }
00443 }
00444 
00445 uint32_t Field_blob::pack_length() const
00446 {
00447   return (uint32_t) (sizeof(uint32_t) + portable_sizeof_char_ptr);
00448 }
00449 
00450 unsigned char *Field_blob::pack(unsigned char *to, const unsigned char *from,
00451                                 uint32_t max_length, bool low_byte_first)
00452 {
00453   unsigned char *save= ptr;
00454   ptr= (unsigned char*) from;
00455   uint32_t length= get_length();      // Length of from string
00456 
00457   /*
00458     Store max length, which will occupy packlength bytes. If the max
00459     length given is smaller than the actual length of the blob, we
00460     just store the initial bytes of the blob.
00461   */
00462   store_length(to, min(length, max_length), low_byte_first);
00463 
00464   /*
00465     Store the actual blob data, which will occupy 'length' bytes.
00466    */
00467   if (length > 0)
00468   {
00469     from= get_ptr();
00470     memcpy(to+sizeof(uint32_t), from,length);
00471   }
00472 
00473   ptr= save;          // Restore org row pointer
00474   return(to+sizeof(uint32_t)+length);
00475 }
00476 
00494 const unsigned char *Field_blob::unpack(unsigned char *,
00495                                         const unsigned char *from,
00496                                         uint32_t,
00497                                         bool low_byte_first)
00498 {
00499   uint32_t const length= get_length(from, low_byte_first);
00500   getTable()->setWriteSet(position());
00501   store(reinterpret_cast<const char*>(from) + sizeof(uint32_t),
00502         length, field_charset);
00503   return(from + sizeof(uint32_t) + length);
00504 }
00505 
00508 unsigned char *
00509 Field_blob::pack_key(unsigned char *to, const unsigned char *from, uint32_t max_length,
00510                      bool )
00511 {
00512   unsigned char *save= ptr;
00513   ptr= (unsigned char*) from;
00514   uint32_t length=get_length();        // Length of from string
00515   uint32_t local_char_length= ((field_charset->mbmaxlen > 1) ?
00516                            max_length/field_charset->mbmaxlen : max_length);
00517   if (length)
00518     from= get_ptr();
00519   if (length > local_char_length)
00520     local_char_length= my_charpos(field_charset, from, from+length,
00521                                   local_char_length);
00522   set_if_smaller(length, local_char_length);
00523   *to++= (unsigned char) length;
00524   if (max_length > 255)       // 2 byte length
00525     *to++= (unsigned char) (length >> 8);
00526   memcpy(to, from, length);
00527   ptr=save;         // Restore org row pointer
00528   return to+length;
00529 }
00530 
00531 
00539 uint32_t Field_blob::max_display_length()
00540 {
00541     return (uint32_t) 4294967295U;
00542 }
00543 
00544 } /* namespace drizzled */