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