Drizzled Public API Documentation

to_days.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 Sun Microsystems, Inc.
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; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <drizzled/function/time/to_days.h>
00023 #include <drizzled/error.h>
00024 #include <drizzled/temporal.h>
00025 
00026 namespace drizzled
00027 {
00028 
00029 /* 
00030  * We intepret the first argument as a DateTime and then convert
00031  * it to a Julian Day Number and return it.
00032  */
00033 int64_t Item_func_to_days::val_int()
00034 {
00035   assert(fixed);
00036 
00037   /* We return NULL from FROM_DAYS() only when supplied a NULL argument */
00038   if (args[0]->null_value)
00039   {
00040     null_value= true;
00041     return false;
00042   }
00043 
00044   /*
00045    * We attempt to convert the first argument into a
00046    * temporal value.  If the conversion is successful, 
00047    * we know that a conversion to a Julian Day Number
00048    * is always possible.  Upon successful conversion, 
00049    * we return the Julian Day Number.  If no conversion
00050    * was possible into a temporal value, we throw an 
00051    * error and return 0, setting the null_value flag to true.
00052    */
00053   /* Grab the first argument as a DateTime object */
00054   DateTime temporal;
00055   Item_result arg0_result_type= args[0]->result_type();
00056   
00057   switch (arg0_result_type)
00058   {
00059     case REAL_RESULT:
00060     case DECIMAL_RESULT: 
00061       /* 
00062        * For doubles supplied, interpret the arg as a string, 
00063        * so intentionally fall-through here...
00064        * This allows us to accept double parameters like 
00065        * 19971231235959.01 and interpret it the way MySQL does:
00066        * as a TIMESTAMP-like thing with a microsecond component.
00067        * Ugh, but need to keep backwards-compat.
00068        */
00069     case STRING_RESULT:
00070       {
00071         char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
00072         String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
00073         String *res= args[0]->val_str(&tmp);
00074 
00075         if (! res)
00076         {
00077           /* 
00078            * Likely a nested function issue where the nested
00079            * function had bad input.  We rely on the nested
00080            * function my_error() and simply return false here.
00081            */
00082           return false;
00083         }
00084 
00085         if (res != &tmp)
00086         {
00087           tmp.copy(*res);
00088         }
00089 
00090         if (! temporal.from_string(tmp.c_ptr(), tmp.length()))
00091         {
00092           /* 
00093           * Could not interpret the function argument as a temporal value, 
00094           * so throw an error and return 0
00095           */
00096           my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
00097           return 0;
00098         }
00099       }
00100       break;
00101     case INT_RESULT:
00102       if (temporal.from_int64_t(args[0]->val_int()))
00103         break;
00104       /* Intentionally fall-through on invalid conversion from integer */
00105     default:
00106       {
00107         /* 
00108         * Could not interpret the function argument as a temporal value, 
00109         * so throw an error and return 0
00110         */
00111         null_value= true;
00112         char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
00113         String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
00114         String *res;
00115 
00116         res= args[0]->val_str(&tmp);
00117 
00118         if (! res)
00119         {
00120           /* 
00121            * Likely a nested function issue where the nested
00122            * function had bad input.  We rely on the nested
00123            * function my_error() and simply return false here.
00124            */
00125           return false;
00126         }
00127 
00128         if (res != &tmp)
00129         {
00130           tmp.copy(*res);
00131         }
00132 
00133         my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
00134         return 0;
00135       }
00136   }
00137   int64_t julian_day_number;
00138   temporal.to_julian_day_number(&julian_day_number);
00139   return julian_day_number;
00140 }
00141 
00142 int64_t Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
00143 {
00144   assert(fixed);
00145 
00146   /*
00147    * We attempt to convert the first argument into a
00148    * temporal value.  If the conversion is successful, 
00149    * we know that a conversion to a Julian Day Number
00150    * is always possible. Depending on whether the 
00151    * first argument is a Date, or a DateTime with no
00152    * time-portion, we return the Julian Day Number or
00153    * the appropriate end-point integer.
00154    */
00155   /* Grab the first argument as a DateTime object */
00156   DateTime temporal;
00157   Item_result arg0_result_type= args[0]->result_type();
00158   
00159   switch (arg0_result_type)
00160   {
00161     case REAL_RESULT:
00162     case DECIMAL_RESULT: 
00163       /* 
00164        * For doubles supplied, interpret the arg as a string, 
00165        * so intentionally fall-through here...
00166        * This allows us to accept double parameters like 
00167        * 19971231235959.01 and interpret it the way MySQL does:
00168        * as a TIMESTAMP-like thing with a microsecond component.
00169        * Ugh, but need to keep backwards-compat.
00170        */
00171     case STRING_RESULT:
00172       {
00173         char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
00174         String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
00175         String *res= args[0]->val_str(&tmp);
00176 
00177         if (! res)
00178         {
00179           /* 
00180            * Likely a nested function issue where the nested
00181            * function had bad input.  We rely on the nested
00182            * function my_error() and simply return false here.
00183            */
00184           return 0;
00185         }
00186 
00187         if (res != &tmp)
00188         {
00189           tmp.copy(*res);
00190         }
00191 
00192         if (! temporal.from_string(tmp.c_ptr(), tmp.length()))
00193         {
00194           /* 
00195           * Could not interpret the function argument as a temporal value, 
00196           * so throw an error and return 0
00197           */
00198           my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
00199           return 0;
00200         }
00201       }
00202       break;
00203     case INT_RESULT:
00204       if (temporal.from_int64_t(args[0]->val_int()))
00205         break;
00206       /* Intentionally fall-through on invalid conversion from integer */
00207     default:
00208       {
00209         /* 
00210         * Could not interpret the function argument as a temporal value, 
00211         * so throw an error and return 0
00212         */
00213         null_value= true;
00214         char buff[DRIZZLE_MAX_LENGTH_DATETIME_AS_STRING];
00215         String tmp(buff,sizeof(buff), &my_charset_utf8_bin);
00216         String *res;
00217 
00218         res= args[0]->val_str(&tmp);
00219 
00220         if (! res)
00221         {
00222           /* 
00223            * Likely a nested function issue where the nested
00224            * function had bad input.  We rely on the nested
00225            * function my_error() and simply return false here.
00226            */
00227           return 0;
00228         }
00229 
00230         if (res != &tmp)
00231         {
00232           tmp.copy(*res);
00233         }
00234 
00235         my_error(ER_INVALID_DATETIME_VALUE, MYF(0), tmp.c_ptr());
00236         return 0;
00237       }
00238   }
00239 
00240   if (null_value == true)
00241   {
00242     /* got NULL, leave the incl_endp intact */
00243     return INT64_MIN;
00244   }
00245 
00246   int64_t julian_day_number;
00247   temporal.to_julian_day_number(&julian_day_number);
00248 
00249   if (args[0]->field_type() == DRIZZLE_TYPE_DATE)
00250   {
00251     /* TO_DAYS() is strictly monotonic for dates, leave incl_endp intact */
00252     return julian_day_number;
00253   }
00254 
00255   /*
00256     Handle the special but practically useful case of datetime values that
00257     point to day bound ("strictly less" comparison stays intact):
00258 
00259       col < '2007-09-15 00:00:00'  -> TO_DAYS(col) <  TO_DAYS('2007-09-15')
00260 
00261     which is different from the general case ("strictly less" changes to
00262     "less or equal"):
00263 
00264       col < '2007-09-15 12:34:56'  -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
00265   */
00266   if (!left_endp && ! (
00267                     temporal.hours() 
00268                     || temporal.minutes()
00269                     || temporal.seconds() 
00270                     || temporal.useconds()
00271                     || temporal.nseconds()
00272                     )
00273                     )
00274     ; /* do nothing */
00275   else
00276     *incl_endp= true;
00277   return julian_day_number;
00278 }
00279 
00280 } /* namespace drizzled */