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 
00028 #include <string>
00029 #include <algorithm>
00030 
00031 using namespace std;
00032 
00033 namespace drizzled
00034 {
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 * 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 * 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     size_t dummy_offset;
00164     if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
00165     {
00166       Field_blob::store_length(length);
00167       memmove(ptr+sizeof(uint32_t), &from, sizeof(char*));
00168       return 0;
00169     }
00170     if (tmpstr.copy(from, length, cs))
00171       goto oom_error;
00172     from= tmpstr.ptr();
00173   }
00174 
00175   new_length= min(max_data_length(), field_charset->mbmaxlen * length);
00176   if (value.alloc(new_length))
00177     goto oom_error;
00178 
00179   /*
00180     "length" is OK as "nchars" argument to well_formed_copy_nchars as this
00181     is never used to limit the length of the data. The cut of long data
00182     is done with the new_length value.
00183   */
00184   copy_length= well_formed_copy_nchars(field_charset,
00185                                        (char*) value.ptr(), new_length,
00186                                        cs, from, length,
00187                                        length,
00188                                        &well_formed_error_pos,
00189                                        &cannot_convert_error_pos,
00190                                        &from_end_pos);
00191 
00192   Field_blob::store_length(copy_length);
00193   tmp= value.ptr();
00194   memmove(ptr+sizeof(uint32_t), &tmp, sizeof(char*));
00195 
00196   if (check_string_copy_error(this, well_formed_error_pos,
00197                               cannot_convert_error_pos, from + length, cs))
00198     return 2;
00199 
00200   return report_if_important_data(from_end_pos, from + length);
00201 
00202 oom_error:
00203   /* Fatal OOM error */
00204   memset(ptr, 0, Field_blob::pack_length());
00205   return -1;
00206 }
00207 
00208 
00209 int Field_blob::store(double nr)
00210 {
00211   const CHARSET_INFO * const cs=charset();
00212   ASSERT_COLUMN_MARKED_FOR_WRITE;
00213   value.set_real(nr, NOT_FIXED_DEC, cs);
00214   return Field_blob::store(value.ptr(),(uint32_t) value.length(), cs);
00215 }
00216 
00217 
00218 int Field_blob::store(int64_t nr, bool unsigned_val)
00219 {
00220   const CHARSET_INFO * const cs=charset();
00221   ASSERT_COLUMN_MARKED_FOR_WRITE;
00222   value.set_int(nr, unsigned_val, cs);
00223   return Field_blob::store(value.ptr(), (uint32_t) value.length(), cs);
00224 }
00225 
00226 
00227 double Field_blob::val_real(void) const
00228 {
00229   int not_used;
00230   char *end_not_used, *blob;
00231   uint32_t length;
00232   const CHARSET_INFO *cs;
00233 
00234   ASSERT_COLUMN_MARKED_FOR_READ;
00235 
00236   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00237   if (!blob)
00238     return 0.0;
00239   length= get_length(ptr);
00240   cs= charset();
00241   return my_strntod(cs, blob, length, &end_not_used, &not_used);
00242 }
00243 
00244 
00245 int64_t Field_blob::val_int(void) const
00246 {
00247   int not_used;
00248   char *blob;
00249 
00250   ASSERT_COLUMN_MARKED_FOR_READ;
00251 
00252   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00253   if (!blob)
00254     return 0;
00255   uint32_t length= get_length(ptr);
00256   return my_strntoll(charset(),blob,length,10,NULL,&not_used);
00257 }
00258 
00259 String *Field_blob::val_str(String *, String *val_ptr) const
00260 {
00261   char *blob;
00262 
00263   ASSERT_COLUMN_MARKED_FOR_READ;
00264 
00265   memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00266   if (!blob)
00267     val_ptr->set("",0,charset()); // A bit safer than ->length(0)
00268   else
00269     val_ptr->set((const char*) blob,get_length(ptr),charset());
00270   return val_ptr;
00271 }
00272 
00273 
00274 type::Decimal *Field_blob::val_decimal(type::Decimal *decimal_value) const
00275 {
00276   const char *blob;
00277   size_t length;
00278 
00279   ASSERT_COLUMN_MARKED_FOR_READ;
00280 
00281   memcpy(&blob, ptr+sizeof(uint32_t), sizeof(const unsigned char*));
00282   if (!blob)
00283   {
00284     blob= "";
00285     length= 0;
00286   }
00287   else
00288   {
00289     length= get_length(ptr);
00290   }
00291 
00292   decimal_value->store(E_DEC_FATAL_ERROR, blob, length, charset());
00293 
00294   return decimal_value;
00295 }
00296 
00297 
00298 int Field_blob::cmp(const unsigned char *a,uint32_t a_length, const unsigned char *b,
00299         uint32_t b_length)
00300 {
00301   return field_charset->coll->strnncollsp(field_charset,
00302                                           a, a_length, b, b_length,
00303                                           0);
00304 }
00305 
00306 
00307 int Field_blob::cmp_max(const unsigned char *a_ptr, const unsigned char *b_ptr,
00308                         uint32_t max_length)
00309 {
00310   unsigned char *blob1,*blob2;
00311   memcpy(&blob1,a_ptr+sizeof(uint32_t),sizeof(char*));
00312   memcpy(&blob2,b_ptr+sizeof(uint32_t),sizeof(char*));
00313   uint32_t a_len= get_length(a_ptr), b_len= get_length(b_ptr);
00314   set_if_smaller(a_len, max_length);
00315   set_if_smaller(b_len, max_length);
00316   return Field_blob::cmp(blob1,a_len,blob2,b_len);
00317 }
00318 
00319 
00320 int Field_blob::cmp_binary(const unsigned char *a_ptr, const unsigned char *b_ptr,
00321                            uint32_t max_length)
00322 {
00323   char *a,*b;
00324   uint32_t diff;
00325   uint32_t a_length,b_length;
00326   memcpy(&a,a_ptr+sizeof(uint32_t),sizeof(char*));
00327   memcpy(&b,b_ptr+sizeof(uint32_t),sizeof(char*));
00328 
00329   a_length= get_length(a_ptr);
00330 
00331   if (a_length > max_length)
00332     a_length= max_length;
00333 
00334   b_length= get_length(b_ptr);
00335 
00336   if (b_length > max_length)
00337     b_length= max_length;
00338 
00339   diff= memcmp(a,b,min(a_length,b_length));
00340 
00341   return diff ? diff : (unsigned int) (a_length - b_length);
00342 }
00343 
00344 /* The following is used only when comparing a key */
00345 uint32_t Field_blob::get_key_image(unsigned char *buff, uint32_t length)
00346 {
00347   uint32_t blob_length= get_length(ptr);
00348   unsigned char *blob;
00349 
00350   get_ptr(&blob);
00351   uint32_t local_char_length= length / field_charset->mbmaxlen;
00352   local_char_length= my_charpos(field_charset, blob, blob + blob_length,
00353                           local_char_length);
00354   set_if_smaller(blob_length, local_char_length);
00355 
00356   if ((uint32_t) length > blob_length)
00357   {
00358     /*
00359       Must clear this as we do a memcmp in optimizer/range.cc to detect
00360       identical keys
00361     */
00362     memset(buff+HA_KEY_BLOB_LENGTH+blob_length, 0, (length-blob_length));
00363     length=(uint32_t) blob_length;
00364   }
00365   int2store(buff,length);
00366   memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
00367   return HA_KEY_BLOB_LENGTH+length;
00368 }
00369 
00370 
00371 uint32_t Field_blob::get_key_image(basic_string<unsigned char> &buff, uint32_t length)
00372 {
00373   uint32_t blob_length= get_length(ptr);
00374   unsigned char *blob;
00375 
00376   get_ptr(&blob);
00377   uint32_t local_char_length= length / field_charset->mbmaxlen;
00378   local_char_length= my_charpos(field_charset, blob, blob + blob_length,
00379                                 local_char_length);
00380   set_if_smaller(blob_length, local_char_length);
00381 
00382   unsigned char len_buff[HA_KEY_BLOB_LENGTH];
00383   int2store(len_buff,length);
00384   buff.append(len_buff);
00385   buff.append(blob, blob_length);
00386 
00387   if (length > blob_length)
00388   {
00389     /*
00390       Must clear this as we do a memcmp in optimizer/range.cc to detect
00391       identical keys
00392     */
00393 
00394     buff.append(length-blob_length, '0');
00395   }
00396   return HA_KEY_BLOB_LENGTH+length;
00397 }
00398 
00399 void Field_blob::set_key_image(const unsigned char *buff,uint32_t length)
00400 {
00401   length= uint2korr(buff);
00402   (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, field_charset);
00403 }
00404 
00405 int Field_blob::key_cmp(const unsigned char *key_ptr, uint32_t max_key_length)
00406 {
00407   unsigned char *blob1;
00408   uint32_t blob_length=get_length(ptr);
00409   memcpy(&blob1,ptr+sizeof(uint32_t),sizeof(char*));
00410   const CHARSET_INFO * const cs= charset();
00411   uint32_t local_char_length= max_key_length / cs->mbmaxlen;
00412   local_char_length= my_charpos(cs, blob1, blob1+blob_length,
00413                                 local_char_length);
00414   set_if_smaller(blob_length, local_char_length);
00415   return Field_blob::cmp(blob1, blob_length,
00416        key_ptr+HA_KEY_BLOB_LENGTH,
00417        uint2korr(key_ptr));
00418 }
00419 
00420 int Field_blob::key_cmp(const unsigned char *a,const unsigned char *b)
00421 {
00422   return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
00423        b+HA_KEY_BLOB_LENGTH, uint2korr(b));
00424 }
00425 
00426 uint32_t Field_blob::sort_length() const
00427 {
00428   return (uint32_t) (getTable()->getSession()->variables.max_sort_length +
00429                      (field_charset == &my_charset_bin ? 0 : sizeof(uint32_t)));
00430 }
00431 
00432 void Field_blob::sort_string(unsigned char *to,uint32_t length)
00433 {
00434   unsigned char *blob;
00435   uint32_t blob_length=get_length();
00436 
00437   if (!blob_length)
00438     memset(to, 0, length);
00439   else
00440   {
00441     if (field_charset == &my_charset_bin)
00442     {
00443       unsigned char *pos;
00444 
00445       /*
00446         Store length of blob last in blob to shorter blobs before longer blobs
00447       */
00448       length-= sizeof(uint32_t); // size of stored blob length
00449       pos= to+length;
00450 
00451       mi_int4store(pos, blob_length);
00452     }
00453     memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
00454 
00455     blob_length=my_strnxfrm(field_charset,
00456                             to, length, blob, blob_length);
00457     assert(blob_length == length);
00458   }
00459 }
00460 
00461 uint32_t Field_blob::pack_length() const
00462 {
00463   return (uint32_t) (sizeof(uint32_t) + portable_sizeof_char_ptr);
00464 }
00465 
00466 void Field_blob::sql_type(String &res) const
00467 {
00468   if (charset() == &my_charset_bin)
00469     res.set_ascii(STRING_WITH_LEN("blob"));
00470   else
00471     res.set_ascii(STRING_WITH_LEN("text"));
00472 }
00473 
00474 unsigned char *Field_blob::pack(unsigned char *to, const unsigned char *from,
00475                                 uint32_t max_length, bool low_byte_first)
00476 {
00477   unsigned char *save= ptr;
00478   ptr= (unsigned char*) from;
00479   uint32_t length= get_length();      // Length of from string
00480 
00481   /*
00482     Store max length, which will occupy packlength bytes. If the max
00483     length given is smaller than the actual length of the blob, we
00484     just store the initial bytes of the blob.
00485   */
00486   store_length(to, min(length, max_length), low_byte_first);
00487 
00488   /*
00489     Store the actual blob data, which will occupy 'length' bytes.
00490    */
00491   if (length > 0)
00492   {
00493     get_ptr((unsigned char**) &from);
00494     memcpy(to+sizeof(uint32_t), from,length);
00495   }
00496 
00497   ptr= save;          // Restore org row pointer
00498   return(to+sizeof(uint32_t)+length);
00499 }
00500 
00518 const unsigned char *Field_blob::unpack(unsigned char *,
00519                                         const unsigned char *from,
00520                                         uint32_t,
00521                                         bool low_byte_first)
00522 {
00523   uint32_t const length= get_length(from, low_byte_first);
00524   getTable()->setWriteSet(position());
00525   store(reinterpret_cast<const char*>(from) + sizeof(uint32_t),
00526         length, field_charset);
00527   return(from + sizeof(uint32_t) + length);
00528 }
00529 
00532 unsigned char *
00533 Field_blob::pack_key(unsigned char *to, const unsigned char *from, uint32_t max_length,
00534                      bool )
00535 {
00536   unsigned char *save= ptr;
00537   ptr= (unsigned char*) from;
00538   uint32_t length=get_length();        // Length of from string
00539   uint32_t local_char_length= ((field_charset->mbmaxlen > 1) ?
00540                            max_length/field_charset->mbmaxlen : max_length);
00541   if (length)
00542     get_ptr((unsigned char**) &from);
00543   if (length > local_char_length)
00544     local_char_length= my_charpos(field_charset, from, from+length,
00545                                   local_char_length);
00546   set_if_smaller(length, local_char_length);
00547   *to++= (unsigned char) length;
00548   if (max_length > 255)       // 2 byte length
00549     *to++= (unsigned char) (length >> 8);
00550   memcpy(to, from, length);
00551   ptr=save;         // Restore org row pointer
00552   return to+length;
00553 }
00554 
00555 
00563 uint32_t Field_blob::max_display_length()
00564 {
00565     return (uint32_t) 4294967295U;
00566 }
00567 
00568 } /* namespace drizzled */