Drizzled Public API Documentation

date.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 #include <config.h>
00022 #include <boost/lexical_cast.hpp>
00023 
00024 #include <drizzled/field/date.h>
00025 #include <drizzled/error.h>
00026 #include <drizzled/table.h>
00027 #include <drizzled/temporal.h>
00028 #include <drizzled/session.h>
00029 #include <drizzled/time_functions.h>
00030 #include <drizzled/current_session.h>
00031 
00032 #include <math.h>
00033 
00034 #include <sstream>
00035 #include <string>
00036 
00037 namespace drizzled
00038 {
00039 
00040 
00041 /****************************************************************************
00042 ** Drizzle date type stored in 3 bytes
00043 ** In number context: YYYYMMDD
00044 ****************************************************************************/
00045 
00046 /*
00047   Store string into a date field
00048 
00049   SYNOPSIS
00050     Field_date::store()
00051     from                Date string
00052     len                 Length of date field
00053     cs                  Character set (not used)
00054 
00055   RETURN
00056     0  ok
00057     1  Value was cut during conversion
00058     2  Wrong date string
00059     3  Datetime value that was cut (warning level NOTE)
00060        This is used by opt_range.cc:get_mm_leaf(). Note that there is a
00061        nearly-identical class Field_date doesn't ever return 3 from its
00062        store function.
00063 */
00064 int Field_date::store(const char *from,
00065                          uint32_t len,
00066                          const CHARSET_INFO * const )
00067 {
00068   /* 
00069    * Try to create a DateTime from the supplied string.  Throw an error
00070    * if unable to create a valid DateTime.  A DateTime is used so that
00071    * automatic conversion from the higher-storage DateTime can be used
00072    * and matches on datetime format strings can occur.
00073    */
00074   ASSERT_COLUMN_MARKED_FOR_WRITE;
00075   DateTime temporal;
00076   if (! temporal.from_string(from, (size_t) len))
00077   {
00078     my_error(ER_INVALID_DATE_VALUE, MYF(ME_FATALERROR), from);
00079     return 2;
00080   }
00081   /* Create the stored integer format. @TODO This should go away. Should be up to engine... */
00082   uint32_t int_value= (temporal.years() * 10000) + (temporal.months() * 100) + temporal.days();
00083   int4store(ptr, int_value);
00084   return 0;
00085 }
00086 
00087 int Field_date::store(double from)
00088 {
00089   ASSERT_COLUMN_MARKED_FOR_WRITE;
00090   if (from < 0.0 || from > 99991231235959.0)
00091   {
00092     /* Convert the double to a string using stringstream */
00093     std::stringstream ss;
00094     std::string tmp;
00095     ss.precision(18); /* 18 places should be fine for error display of double input. */
00096     ss << from; ss >> tmp;
00097 
00098     my_error(ER_INVALID_DATE_VALUE, MYF(ME_FATALERROR), tmp.c_str());
00099     return 2;
00100   }
00101   return Field_date::store((int64_t) rint(from), false);
00102 }
00103 
00104 int Field_date::store(int64_t from, bool)
00105 {
00106   /* 
00107    * Try to create a DateTime from the supplied integer.  Throw an error
00108    * if unable to create a valid DateTime.  
00109    */
00110   ASSERT_COLUMN_MARKED_FOR_WRITE;
00111   DateTime temporal;
00112   if (! temporal.from_int64_t(from))
00113   {
00114     /* Convert the integer to a string using boost::lexical_cast */
00115     std::string tmp(boost::lexical_cast<std::string>(from)); 
00116 
00117     my_error(ER_INVALID_DATE_VALUE, MYF(ME_FATALERROR), tmp.c_str());
00118     return 2;
00119   }
00120 
00121   /* Create the stored integer format. @TODO This should go away. Should be up to engine... */
00122   uint32_t int_value= (temporal.years() * 10000) + (temporal.months() * 100) + temporal.days();
00123   int4store(ptr, int_value);
00124 
00125   return 0;
00126 }
00127 
00128 int Field_date::store_time(type::Time &ltime,
00129                            type::timestamp_t time_type)
00130 {
00131   long tmp;
00132   int error= 0;
00133   if (time_type == type::DRIZZLE_TIMESTAMP_DATE || time_type == type::DRIZZLE_TIMESTAMP_DATETIME)
00134   {
00135     tmp= ltime.year*10000 + ltime.month*100 + ltime.day;
00136 
00137     Session *session= getTable() ? getTable()->in_use : current_session;
00138     type::cut_t cut_error= type::VALID;
00139     if (ltime.check(tmp != 0,
00140                      (TIME_FUZZY_DATE |
00141                       (session->variables.sql_mode & (MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), cut_error))
00142     {
00143       char buff[type::Time::MAX_STRING_LENGTH];
00144       String str(buff, sizeof(buff), &my_charset_utf8_general_ci);
00145       ltime.convert(str, type::DRIZZLE_TIMESTAMP_DATE);
00146       set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
00147                            str.ptr(), str.length(), type::DRIZZLE_TIMESTAMP_DATE, 1);
00148     }
00149 
00150     error= static_cast<int>(cut_error);
00151 
00152     if (not error && ltime.time_type != type::DRIZZLE_TIMESTAMP_DATE &&
00153         (ltime.hour || ltime.minute || ltime.second || ltime.second_part))
00154     {
00155       char buff[type::Time::MAX_STRING_LENGTH];
00156       String str(buff, sizeof(buff), &my_charset_utf8_general_ci);
00157       ltime.convert(str);
00158       set_datetime_warning(DRIZZLE_ERROR::WARN_LEVEL_NOTE,
00159                            ER_WARN_DATA_TRUNCATED,
00160                            str.ptr(), str.length(), type::DRIZZLE_TIMESTAMP_DATE, 1);
00161       error= 3;
00162     }
00163   }
00164   else
00165   {
00166     tmp=0;
00167     error= 1;
00168     set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
00169   }
00170 
00171   int4store(ptr,tmp);
00172 
00173   return error;
00174 }
00175 
00176 double Field_date::val_real(void) const
00177 {
00178   return (double) Field_date::val_int();
00179 }
00180 
00181 int64_t Field_date::val_int(void) const
00182 {
00183   uint32_t j;
00184 
00185   ASSERT_COLUMN_MARKED_FOR_READ;
00186 
00187   j= uint4korr(ptr);
00188 
00189   return (int64_t) j;
00190 }
00191 
00192 String *Field_date::val_str(String *val_buffer, String *) const
00193 {
00194   val_buffer->alloc(field_length);
00195   val_buffer->length(field_length);
00196   uint32_t tmp=(uint32_t) uint4korr(ptr);
00197   int32_t part;
00198   char *pos=(char*) val_buffer->ptr()+10;
00199 
00200   ASSERT_COLUMN_MARKED_FOR_READ;
00201 
00202   /* Open coded to get more speed */
00203   *pos--=0;         // End NULL
00204   part=(int32_t) (tmp % 100);
00205   *pos--= (char) ('0'+part%10);
00206   *pos--= (char) ('0'+part/10);
00207   *pos--= '-';
00208   part=(int32_t) (tmp/100%100);
00209   *pos--= (char) ('0'+part%10);
00210   *pos--= (char) ('0'+part/10);
00211   *pos--= '-';
00212   part=(int32_t) (tmp/10000);
00213   *pos--= (char) ('0'+part%10); part/=10;
00214   *pos--= (char) ('0'+part%10); part/=10;
00215   *pos--= (char) ('0'+part%10); part/=10;
00216   *pos=   (char) ('0'+part);
00217   return val_buffer;
00218 }
00219 
00220 bool Field_date::get_date(type::Time &ltime, uint32_t fuzzydate) const
00221 {
00222   uint32_t tmp=(uint32_t) uint4korr(ptr);
00223   ltime.day=    (int) (tmp%100);
00224   ltime.month=  (int) (tmp/100%100);
00225   ltime.year=     (int) (tmp/10000);
00226   ltime.time_type= type::DRIZZLE_TIMESTAMP_DATE;
00227   ltime.hour= ltime.minute= ltime.second= ltime.second_part= ltime.neg= 0;
00228 
00229   return ((!(fuzzydate & TIME_FUZZY_DATE) && (!ltime.month || !ltime.day)) ?
00230           1 : 0);
00231 }
00232 
00233 bool Field_date::get_time(type::Time &ltime) const
00234 {
00235   return Field_date::get_date(ltime ,0);
00236 }
00237 
00238 int Field_date::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
00239 {
00240   uint32_t a,b;
00241   a=(uint32_t) uint4korr(a_ptr);
00242   b=(uint32_t) uint4korr(b_ptr);
00243   return (a < b) ? -1 : (a > b) ? 1 : 0;
00244 }
00245 
00246 void Field_date::sort_string(unsigned char *to,uint32_t )
00247 {
00248   to[0] = ptr[3];
00249   to[1] = ptr[2];
00250   to[2] = ptr[1];
00251   to[3] = ptr[0];
00252 }
00253 
00254 void Field_date::sql_type(String &res) const
00255 {
00256   res.set_ascii(STRING_WITH_LEN("date"));
00257 }
00258 
00259 } /* namespace drizzled */