Drizzled Public API Documentation

field_conv.cc
Go to the documentation of this file.
00001 /* Copyright (C) 2000-2003 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 
00027 #include <config.h>
00028 
00029 #include <drizzled/error.h>
00030 #include <drizzled/table.h>
00031 #include <drizzled/session.h>
00032 #include <drizzled/current_session.h>
00033 
00034 #include <drizzled/copy_field.h>
00035 #include <drizzled/field/blob.h>
00036 #include <drizzled/field/date.h>
00037 #include <drizzled/field/datetime.h>
00038 #include <drizzled/field/decimal.h>
00039 #include <drizzled/field/double.h>
00040 #include <drizzled/field/enum.h>
00041 #include <drizzled/field/epoch.h>
00042 #include <drizzled/field/int32.h>
00043 #include <drizzled/field/int64.h>
00044 #include <drizzled/field/null.h>
00045 #include <drizzled/field/num.h>
00046 #include <drizzled/field/num.h>
00047 #include <drizzled/field/real.h>
00048 #include <drizzled/field/str.h>
00049 #include <drizzled/field/varstring.h>
00050 #include <drizzled/util/test.h>
00051 #include <drizzled/system_variables.h>
00052 
00053 namespace drizzled {
00054 
00055 static void do_field_eq(CopyField *copy)
00056 {
00057   memcpy(copy->to_ptr, copy->from_ptr, copy->from_length);
00058 }
00059 
00060 static void do_field_1(CopyField *copy)
00061 {
00062   copy->to_ptr[0]= copy->from_ptr[0];
00063 }
00064 
00065 static void do_field_2(CopyField *copy)
00066 {
00067   copy->to_ptr[0]= copy->from_ptr[0];
00068   copy->to_ptr[1]= copy->from_ptr[1];
00069 }
00070 
00071 static void do_field_3(CopyField *copy)
00072 {
00073   copy->to_ptr[0]= copy->from_ptr[0];
00074   copy->to_ptr[1]= copy->from_ptr[1];
00075   copy->to_ptr[2]= copy->from_ptr[2];
00076 }
00077 
00078 static void do_field_4(CopyField *copy)
00079 {
00080   copy->to_ptr[0]= copy->from_ptr[0];
00081   copy->to_ptr[1]= copy->from_ptr[1];
00082   copy->to_ptr[2]= copy->from_ptr[2];
00083   copy->to_ptr[3]= copy->from_ptr[3];
00084 }
00085 
00086 static void do_field_6(CopyField *copy)
00087 {                  // For blob field
00088   copy->to_ptr[0]= copy->from_ptr[0];
00089   copy->to_ptr[1]= copy->from_ptr[1];
00090   copy->to_ptr[2]= copy->from_ptr[2];
00091   copy->to_ptr[3]= copy->from_ptr[3];
00092   copy->to_ptr[4]= copy->from_ptr[4];
00093   copy->to_ptr[5]= copy->from_ptr[5];
00094 }
00095 
00096 static void do_field_8(CopyField *copy)
00097 {
00098   copy->to_ptr[0]= copy->from_ptr[0];
00099   copy->to_ptr[1]= copy->from_ptr[1];
00100   copy->to_ptr[2]= copy->from_ptr[2];
00101   copy->to_ptr[3]= copy->from_ptr[3];
00102   copy->to_ptr[4]= copy->from_ptr[4];
00103   copy->to_ptr[5]= copy->from_ptr[5];
00104   copy->to_ptr[6]= copy->from_ptr[6];
00105   copy->to_ptr[7]= copy->from_ptr[7];
00106 }
00107 
00108 
00109 static void do_field_to_null_str(CopyField *copy)
00110 {
00111   if (*copy->from_null_ptr & copy->from_bit)
00112   {
00113     memset(copy->to_ptr, 0, copy->from_length);
00114     copy->to_null_ptr[0]= 1;  // Always bit 1
00115   }
00116   else
00117   {
00118     copy->to_null_ptr[0]= 0;
00119     memcpy(copy->to_ptr, copy->from_ptr, copy->from_length);
00120   }
00121 }
00122 
00123 
00124 static void do_outer_field_to_null_str(CopyField *copy)
00125 {
00126   if (*copy->null_row ||
00127       (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
00128   {
00129     memset(copy->to_ptr, 0, copy->from_length);
00130     copy->to_null_ptr[0]= 1;  // Always bit 1
00131   }
00132   else
00133   {
00134     copy->to_null_ptr[0]= 0;
00135     memcpy(copy->to_ptr, copy->from_ptr, copy->from_length);
00136   }
00137 }
00138 
00139 
00140 int
00141 set_field_to_null(Field *field)
00142 {
00143   if (field->real_maybe_null())
00144   {
00145     field->set_null();
00146     field->reset();
00147     return 0;
00148   }
00149   field->reset();
00150   if (field->getTable()->in_use->count_cuted_fields == CHECK_FIELD_WARN)
00151   {
00152     field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
00153     return 0;
00154   }
00155   if (!field->getTable()->in_use->no_errors)
00156     my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
00157   return -1;
00158 }
00159 
00160 
00178 int
00179 set_field_to_null_with_conversions(Field *field, bool no_conversions)
00180 {
00181   if (field->real_maybe_null())
00182   {
00183     field->set_null();
00184     field->reset();
00185     return 0;
00186   }
00187 
00188   if (no_conversions)
00189     return -1;
00190 
00191   /*
00192     Check if this is a special type, which will get a special walue
00193     when set to NULL (TIMESTAMP fields which allow setting to NULL
00194     are handled by first check).
00195   */
00196   if (field->is_timestamp())
00197   {
00198     ((field::Epoch::pointer) field)->set_time();
00199     return 0;         // Ok to set time to NULL
00200   }
00201 
00202   field->reset();
00203   if (field == field->getTable()->next_number_field)
00204   {
00205     field->getTable()->auto_increment_field_not_null= false;
00206     return 0;         // field is set in fill_record()
00207   }
00208 
00209   if (field->getTable()->in_use->count_cuted_fields == CHECK_FIELD_WARN)
00210   {
00211     field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1);
00212     return 0;
00213   }
00214 
00215   if (!field->getTable()->in_use->no_errors)
00216     my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
00217 
00218   return -1;
00219 }
00220 
00221 
00222 static void do_skip(CopyField *)
00223 {
00224 }
00225 
00226 
00227 static void do_copy_null(CopyField *copy)
00228 {
00229   if (*copy->from_null_ptr & copy->from_bit)
00230   {
00231     *copy->to_null_ptr|= copy->to_bit;
00232     copy->to_field->reset();
00233   }
00234   else
00235   {
00236     *copy->to_null_ptr&= ~copy->to_bit;
00237     (copy->do_copy2)(copy);
00238   }
00239 }
00240 
00241 
00242 static void do_outer_field_null(CopyField *copy)
00243 {
00244   if (*copy->null_row ||
00245       (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
00246   {
00247     *copy->to_null_ptr|=copy->to_bit;
00248     copy->to_field->reset();
00249   }
00250   else
00251   {
00252     *copy->to_null_ptr&= ~copy->to_bit;
00253     (copy->do_copy2)(copy);
00254   }
00255 }
00256 
00257 
00258 static void do_copy_not_null(CopyField *copy)
00259 {
00260   if (copy->to_field->hasDefault() and *copy->from_null_ptr & copy->from_bit)
00261   {
00262     copy->to_field->set_default();
00263   }
00264   else if (*copy->from_null_ptr & copy->from_bit)
00265   {
00266     copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00267                                 ER_WARN_DATA_TRUNCATED, 1);
00268     copy->to_field->reset();
00269   }
00270   else
00271   {
00272     (copy->do_copy2)(copy);
00273   }
00274 }
00275 
00276 
00277 static void do_copy_maybe_null(CopyField *copy)
00278 {
00279   *copy->to_null_ptr&= ~copy->to_bit;
00280   (copy->do_copy2)(copy);
00281 }
00282 
00283 /* timestamp and next_number has special handling in case of NULL values */
00284 
00285 static void do_copy_timestamp(CopyField *copy)
00286 {
00287   if (*copy->from_null_ptr & copy->from_bit)
00288   {
00289     /* Same as in set_field_to_null_with_conversions() */
00290     ((field::Epoch::pointer) copy->to_field)->set_time();
00291   }
00292   else
00293   {
00294     (copy->do_copy2)(copy);
00295   }
00296 }
00297 
00298 
00299 static void do_copy_next_number(CopyField *copy)
00300 {
00301   if (*copy->from_null_ptr & copy->from_bit)
00302   {
00303     /* Same as in set_field_to_null_with_conversions() */
00304     copy->to_field->getTable()->auto_increment_field_not_null= false;
00305     copy->to_field->reset();
00306   }
00307   else
00308   {
00309     (copy->do_copy2)(copy);
00310   }
00311 }
00312 
00313 
00314 static void do_copy_blob(CopyField *copy)
00315 {
00316   ulong length= ((Field_blob*) copy->from_field)->get_length();
00317   ((Field_blob*) copy->to_field)->store_length(length);
00318   memcpy(copy->to_ptr, copy->from_ptr, sizeof(char*));
00319 }
00320 
00321 static void do_conv_blob(CopyField *copy)
00322 {
00323   copy->from_field->val_str_internal(&copy->tmp);
00324   ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
00325                                          copy->tmp.length(),
00326                                          copy->tmp.charset());
00327 }
00328 
00331 static void do_save_blob(CopyField *copy)
00332 {
00333   char buff[MAX_FIELD_WIDTH];
00334   String res(buff, sizeof(buff), copy->tmp.charset());
00335   copy->from_field->val_str_internal(&res);
00336   copy->tmp.copy(res);
00337   ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
00338                                          copy->tmp.length(),
00339                                          copy->tmp.charset());
00340 }
00341 
00342 
00343 static void do_field_string(CopyField *copy)
00344 {
00345   char buff[MAX_FIELD_WIDTH];
00346   copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset());
00347   copy->from_field->val_str_internal(&copy->tmp);
00348   copy->to_field->store(copy->tmp.data(),copy->tmp.length(), copy->tmp.charset());
00349 }
00350 
00351 
00352 static void do_field_enum(CopyField *copy)
00353 {
00354   if (copy->from_field->val_int() == 0)
00355     ((Field_enum *) copy->to_field)->store_type((uint64_t) 0);
00356   else
00357     do_field_string(copy);
00358 }
00359 
00360 
00361 static void do_field_int(CopyField *copy)
00362 {
00363   int64_t value= copy->from_field->val_int();
00364   copy->to_field->store(value,
00365                         test(copy->from_field->flags & UNSIGNED_FLAG));
00366 }
00367 
00368 static void do_field_real(CopyField *copy)
00369 {
00370   double value=copy->from_field->val_real();
00371   copy->to_field->store(value);
00372 }
00373 
00374 
00375 static void do_field_decimal(CopyField *copy)
00376 {
00377   type::Decimal value;
00378   copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
00379 }
00380 
00381 
00387 static void do_cut_string(CopyField *copy)
00388 {
00389   const charset_info_st * const cs= copy->from_field->charset();
00390   memcpy(copy->to_ptr, copy->from_ptr, copy->to_length);
00391 
00392   /* Check if we loosed any important characters */
00393   if (cs->cset->scan(cs,
00394                      (char*) copy->from_ptr + copy->to_length,
00395                      (char*) copy->from_ptr + copy->from_length,
00396                      MY_SEQ_SPACES) < copy->from_length - copy->to_length)
00397   {
00398     copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00399                                 ER_WARN_DATA_TRUNCATED, 1);
00400   }
00401 }
00402 
00403 
00409 static void do_cut_string_complex(CopyField *copy)
00410 {           // Shorter string field
00411   int well_formed_error;
00412   const charset_info_st * const cs= copy->from_field->charset();
00413   const unsigned char *from_end= copy->from_ptr + copy->from_length;
00414   uint32_t copy_length= cs->cset->well_formed_len(*cs, str_ref(copy->from_ptr, from_end), copy->to_length / cs->mbmaxlen, &well_formed_error);
00415   if (copy->to_length < copy_length)
00416     copy_length= copy->to_length;
00417   memcpy(copy->to_ptr, copy->from_ptr, copy_length);
00418 
00419   /* Check if we lost any important characters */
00420   if (well_formed_error ||
00421       cs->cset->scan(cs, (char*) copy->from_ptr + copy_length,
00422                      (char*) from_end,
00423                      MY_SEQ_SPACES) < (copy->from_length - copy_length))
00424   {
00425     copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00426                                 ER_WARN_DATA_TRUNCATED, 1);
00427   }
00428 
00429   if (copy_length < copy->to_length)
00430     cs->cset->fill(cs, (char*) copy->to_ptr + copy_length,
00431                    copy->to_length - copy_length, ' ');
00432 }
00433 
00434 
00435 
00436 
00437 static void do_expand_binary(CopyField *copy)
00438 {
00439   const charset_info_st * const cs= copy->from_field->charset();
00440   memcpy(copy->to_ptr, copy->from_ptr, copy->from_length);
00441   cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
00442                  copy->to_length-copy->from_length, '\0');
00443 }
00444 
00445 
00446 
00447 static void do_expand_string(CopyField *copy)
00448 {
00449   const charset_info_st * const cs= copy->from_field->charset();
00450   memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
00451   cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
00452                  copy->to_length-copy->from_length, ' ');
00453 }
00454 
00455 
00456 static void do_varstring1(CopyField *copy)
00457 {
00458   uint32_t length= (uint32_t) *(unsigned char*) copy->from_ptr;
00459   if (length > copy->to_length- 1)
00460   {
00461     length= copy->to_length - 1;
00462     if (copy->from_field->getTable()->in_use->count_cuted_fields)
00463     {
00464       copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00465                                   ER_WARN_DATA_TRUNCATED, 1);
00466     }
00467   }
00468   *(unsigned char*) copy->to_ptr= (unsigned char) length;
00469   memcpy(copy->to_ptr+1, copy->from_ptr + 1, length);
00470 }
00471 
00472 
00473 static void do_varstring1_mb(CopyField *copy)
00474 {
00475   int well_formed_error;
00476   const charset_info_st * const cs= copy->from_field->charset();
00477   uint32_t from_length= (uint32_t) *(unsigned char*) copy->from_ptr;
00478   const unsigned char *from_ptr= copy->from_ptr + 1;
00479   uint32_t to_char_length= (copy->to_length - 1) / cs->mbmaxlen;
00480   uint32_t length= cs->cset->well_formed_len(*cs, str_ref(from_ptr, from_length), to_char_length, &well_formed_error);
00481   if (length < from_length)
00482   {
00483     if (current_session->count_cuted_fields)
00484     {
00485       copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
00486     }
00487   }
00488   *copy->to_ptr= (unsigned char) length;
00489   memcpy(copy->to_ptr + 1, from_ptr, length);
00490 }
00491 
00492 
00493 static void do_varstring2(CopyField *copy)
00494 {
00495   uint32_t length= uint2korr(copy->from_ptr);
00496   if (length > copy->to_length- HA_KEY_BLOB_LENGTH)
00497   {
00498     length=copy->to_length-HA_KEY_BLOB_LENGTH;
00499     if (copy->from_field->getTable()->in_use->count_cuted_fields)
00500     {
00501       copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00502                                   ER_WARN_DATA_TRUNCATED, 1);
00503     }
00504   }
00505   int2store(copy->to_ptr,length);
00506   memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, copy->from_ptr + HA_KEY_BLOB_LENGTH,
00507          length);
00508 }
00509 
00510 
00511 static void do_varstring2_mb(CopyField *copy)
00512 {
00513   int well_formed_error;
00514   const charset_info_st * const cs= copy->from_field->charset();
00515   uint32_t char_length= (copy->to_length - HA_KEY_BLOB_LENGTH) / cs->mbmaxlen;
00516   uint32_t from_length= uint2korr(copy->from_ptr);
00517   const unsigned char *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
00518   uint32_t length= cs->cset->well_formed_len(*cs, str_ref(from_beg, from_length), char_length, &well_formed_error);
00519   if (length < from_length)
00520   {
00521     if (current_session->count_cuted_fields)
00522     {
00523       copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
00524                                   ER_WARN_DATA_TRUNCATED, 1);
00525     }
00526   }
00527   int2store(copy->to_ptr, length);
00528   memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, length);
00529 }
00530 
00531 
00532 /***************************************************************************
00533 ** The different functions that fills in a CopyField class
00534 ***************************************************************************/
00535 
00544 void CopyField::set(unsigned char *to,Field *from)
00545 {
00546   from_ptr= from->ptr;
00547   to_ptr= to;
00548   from_length= from->pack_length();
00549   if (from->maybe_null())
00550   {
00551     from_null_ptr= from->null_ptr;
00552     from_bit= from->null_bit;
00553     to_ptr[0]= 1;                             // Null as default value
00554     to_null_ptr= (unsigned char*) to_ptr++;
00555     to_bit= 1;
00556     if (from->getTable()->maybe_null)
00557     {
00558       null_row= &from->getTable()->null_row;
00559       do_copy= do_outer_field_to_null_str;
00560     }
00561     else
00562       do_copy= do_field_to_null_str;
00563   }
00564   else
00565   {
00566     to_null_ptr= 0;                           // For easy debugging
00567     do_copy= do_field_eq;
00568   }
00569 }
00570 
00571 
00572 /*
00573   To do:
00574 
00575   If 'save\ is set to true and the 'from' is a blob field, do_copy is set to
00576   do_save_blob rather than do_conv_blob.  The only differences between them
00577   appears to be:
00578 
00579   - do_save_blob allocates and uses an intermediate buffer before calling
00580     Field_blob::store. Is this in order to trigger the call to
00581     well_formed_copy_nchars, by changing the pointer copy->tmp.ptr()?
00582     That call will take place anyway in all known cases.
00583 
00584   - The above causes a truncation to MAX_FIELD_WIDTH. Is this the intended
00585     effect? Truncation is handled by well_formed_copy_nchars anyway.
00586  */
00587 void CopyField::set(Field *to,Field *from,bool save)
00588 {
00589   if (to->type() == DRIZZLE_TYPE_NULL)
00590   {
00591     to_null_ptr= 0;           // For easy debugging
00592     to_ptr= 0;
00593     do_copy= do_skip;
00594     return;
00595   }
00596   from_field= from;
00597   to_field= to;
00598   from_ptr= from->ptr;
00599   from_length= from->pack_length();
00600   to_ptr= to->ptr;
00601   to_length= to_field->pack_length();
00602 
00603   // set up null handling
00604   from_null_ptr= to_null_ptr= 0;
00605   if (from->maybe_null())
00606   {
00607     from_null_ptr= from->null_ptr;
00608     from_bit= from->null_bit;
00609     if (to_field->real_maybe_null())
00610     {
00611       to_null_ptr= to->null_ptr;
00612       to_bit= to->null_bit;
00613       if (from_null_ptr)
00614       {
00615         do_copy= do_copy_null;
00616       }
00617       else
00618       {
00619         null_row= &from->getTable()->null_row;
00620         do_copy= do_outer_field_null;
00621       }
00622     }
00623     else
00624     {
00625       if (to_field->is_timestamp())
00626       {
00627         do_copy= do_copy_timestamp;               // Automatic timestamp
00628       }
00629       else if (to_field == to_field->getTable()->next_number_field)
00630       {
00631         do_copy= do_copy_next_number;
00632       }
00633       else
00634       {
00635         do_copy= do_copy_not_null;
00636       }
00637     }
00638   }
00639   else if (to_field->real_maybe_null())
00640   {
00641     to_null_ptr= to->null_ptr;
00642     to_bit= to->null_bit;
00643     do_copy= do_copy_maybe_null;
00644   }
00645   else
00646    do_copy= 0;
00647 
00648   if ((to->flags & BLOB_FLAG) && save)
00649     do_copy2= do_save_blob;
00650   else
00651     do_copy2= get_copy_func(to,from);
00652   if (!do_copy)         // Not null
00653     do_copy= do_copy2;
00654 }
00655 
00656 
00657 CopyField::Copy_func *
00658 CopyField::get_copy_func(Field *to,Field *from)
00659 {
00660   bool compatible_db_low_byte_first= (to->getTable()->getShare()->db_low_byte_first ==
00661                                      from->getTable()->getShare()->db_low_byte_first);
00662   if (to->flags & BLOB_FLAG)
00663   {
00664     if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
00665       return do_conv_blob;
00666     if (from_length != to_length || !compatible_db_low_byte_first)
00667     {
00668       // Correct pointer to point at char pointer
00669       to_ptr+= to_length - to->getTable()->getShare()->sizeBlobPtr();
00670       from_ptr+= from_length- from->getTable()->getShare()->sizeBlobPtr();
00671       return do_copy_blob;
00672     }
00673   }
00674   else
00675   {
00676     if (to->result_type() == DECIMAL_RESULT)
00677       return do_field_decimal;
00678       
00679     // Check if identical fields
00680     if (from->result_type() == STRING_RESULT)
00681     {
00682       /*
00683         If we are copying date or datetime's we have to check the dates
00684         if we don't allow 'all' dates.
00685       */
00686       if (to->real_type() != from->real_type() ||
00687           !compatible_db_low_byte_first ||
00688           (((to->getTable()->in_use->variables.sql_mode & (MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) && to->type() == DRIZZLE_TYPE_DATE) || to->type() == DRIZZLE_TYPE_DATETIME))
00689       {
00690         if (from->real_type() == DRIZZLE_TYPE_ENUM)
00691         {
00692           if (to->result_type() != STRING_RESULT)
00693           {
00694             return do_field_int;  // Convert SET to number
00695           }
00696 
00697           return do_field_string;
00698         }
00699       }
00700 
00701       if (to->real_type() == DRIZZLE_TYPE_ENUM)
00702       {
00703         if (!to->eq_def(from))
00704         {
00705           if (from->real_type() == DRIZZLE_TYPE_ENUM &&
00706               to->real_type() == DRIZZLE_TYPE_ENUM)
00707             return do_field_enum;
00708           else
00709             return do_field_string;
00710         }
00711       }
00712       else if (to->charset() != from->charset())
00713         return do_field_string;
00714       else if (to->real_type() == DRIZZLE_TYPE_VARCHAR)
00715       {
00716         /* Field_blob is not part of the Field_varstring hierarchy,
00717           and casting to varstring for calling pack_length_no_ptr()
00718           is always incorrect. Previously the below comparison has
00719           always evaluated to false as pack_length_no_ptr() for BLOB
00720           will return 4 and varstring can only be <= 2.
00721           If your brain slightly bleeds as to why this worked for
00722           so many years, you are in no way alone.
00723         */
00724         if (from->flags & BLOB_FLAG)
00725           return do_field_string;
00726 
00727         if ((static_cast<Field_varstring*>(to))->pack_length_no_ptr() !=
00728             (static_cast<Field_varstring*>(from))->pack_length_no_ptr())
00729         {
00730           return do_field_string;
00731         }
00732 
00733         if (to_length != from_length)
00734         {
00735           return (((Field_varstring*) to)->pack_length_no_ptr() == 1 ?
00736                   (from->charset()->mbmaxlen == 1 ? do_varstring1 :
00737                    do_varstring1_mb) :
00738                   (from->charset()->mbmaxlen == 1 ? do_varstring2 :
00739                    do_varstring2_mb));
00740         }
00741       }
00742       else if (to_length < from_length)
00743       {
00744         return (from->charset()->mbmaxlen == 1 ?
00745                 do_cut_string : do_cut_string_complex);
00746       }
00747       else if (to_length > from_length)
00748       {
00749         if (to->charset() == &my_charset_bin)
00750           return do_expand_binary;
00751         else
00752           return do_expand_string;
00753       }
00754     }
00755     else if (to->real_type() != from->real_type() ||
00756              to_length != from_length ||
00757              !compatible_db_low_byte_first)
00758     {
00759       if (to->result_type() == STRING_RESULT)
00760         return do_field_string;
00761       if (to->result_type() == INT_RESULT)
00762         return do_field_int;
00763 
00764       return do_field_real;
00765     }
00766     else
00767     {
00768       if (!to->eq_def(from) || !compatible_db_low_byte_first)
00769       {
00770         if (to->result_type() == INT_RESULT)
00771           return do_field_int;
00772         else
00773           return do_field_real;
00774       }
00775     }
00776   }
00777   
00778     /* Eq fields */
00779   switch (to_length)
00780   {
00781   case 1: return do_field_1;
00782   case 2: return do_field_2;
00783   case 3: return do_field_3;
00784   case 4: return do_field_4;
00785   case 6: return do_field_6;
00786   case 8: return do_field_8;
00787   }
00788   
00789   return do_field_eq;
00790 }
00791 
00792 
00795 int field_conv(Field *to,Field *from)
00796 {
00797   if (to->real_type() == from->real_type() &&
00798       !(to->type() == DRIZZLE_TYPE_BLOB && to->getTable()->copy_blobs))
00799   {
00800     /* Please god, will someone rewrite this to be readable :( */
00801     if (to->pack_length() == from->pack_length() &&
00802         !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
00803         to->real_type() != DRIZZLE_TYPE_ENUM &&
00804         (to->real_type() != DRIZZLE_TYPE_DECIMAL || (to->field_length == from->field_length && (((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
00805         from->charset() == to->charset() &&
00806   to->getTable()->getShare()->db_low_byte_first == from->getTable()->getShare()->db_low_byte_first &&
00807         (!(to->getTable()->in_use->variables.sql_mode & (MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || (to->type() != DRIZZLE_TYPE_DATE && to->type() != DRIZZLE_TYPE_DATETIME)) &&
00808         (from->real_type() != DRIZZLE_TYPE_VARCHAR || ((Field_varstring*)from)->pack_length_no_ptr() == ((Field_varstring*)to)->pack_length_no_ptr()))
00809     {           // Identical fields
00810       /* This may happen if one does 'UPDATE ... SET x=x' */
00811       if (to->ptr != from->ptr)
00812         memcpy(to->ptr,from->ptr,to->pack_length());
00813       return 0;
00814     }
00815   }
00816   if (to->type() == DRIZZLE_TYPE_BLOB)
00817   {           // Be sure the value is stored
00818     Field_blob *blob=(Field_blob*) to;
00819     from->val_str_internal(&blob->value);
00820     /*
00821       Copy value if copy_blobs is set, or source is not a string and
00822       we have a pointer to its internal string conversion buffer.
00823     */
00824     if (to->getTable()->copy_blobs ||
00825         (!blob->value.is_alloced() &&
00826          from->real_type() != DRIZZLE_TYPE_VARCHAR))
00827       blob->value.copy();
00828     return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
00829   }
00830   if (from->real_type() == DRIZZLE_TYPE_ENUM &&
00831       to->real_type() == DRIZZLE_TYPE_ENUM &&
00832       from->val_int() == 0)
00833   {
00834     ((Field_enum *)(to))->store_type(0);
00835     return 0;
00836   }
00837   else if ((from->result_type() == STRING_RESULT &&
00838             (to->result_type() == STRING_RESULT ||
00839              (from->real_type() != DRIZZLE_TYPE_ENUM))))
00840   {
00841     char buff[MAX_FIELD_WIDTH];
00842     String result(buff,sizeof(buff),from->charset());
00843     from->val_str_internal(&result);
00844     /*
00845       We use c_ptr_quick() here to make it easier if to is a float/double
00846       as the conversion routines will do a copy of the result doesn't
00847       end with \0. Can be replaced with .ptr() when we have our own
00848       string->double conversion.
00849     */
00850     return to->store(result.c_str(),result.length(),from->charset());
00851   }
00852   else if (from->result_type() == REAL_RESULT)
00853   {
00854     return to->store(from->val_real());
00855   }
00856   else if (from->result_type() == DECIMAL_RESULT)
00857   {
00858     type::Decimal buff;
00859     return to->store_decimal(from->val_decimal(&buff));
00860   }
00861   else
00862   {
00863     return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
00864   }
00865 }
00866 
00867 } /* namespace drizzled */