Drizzled Public API Documentation

timestamp_diff.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/timestamp_diff.h>
00023 #include <drizzled/time_functions.h>
00024 
00025 namespace drizzled
00026 {
00027 
00028 int64_t Item_func_timestamp_diff::val_int()
00029 {
00030   type::Time ltime1, ltime2;
00031   int64_t seconds;
00032   long microseconds;
00033   long months= 0;
00034   int neg= 1;
00035 
00036   null_value= 0;
00037   if (args[0]->get_date(ltime1, TIME_NO_ZERO_DATE) ||
00038       args[1]->get_date(ltime2, TIME_NO_ZERO_DATE))
00039     goto null_date;
00040 
00041   if (calc_time_diff(&ltime2,&ltime1, 1,
00042          &seconds, &microseconds))
00043     neg= -1;
00044 
00045   if (int_type == INTERVAL_YEAR ||
00046       int_type == INTERVAL_QUARTER ||
00047       int_type == INTERVAL_MONTH)
00048   {
00049     uint32_t year_beg, year_end, month_beg, month_end, day_beg, day_end;
00050     uint32_t years= 0;
00051     uint32_t second_beg, second_end, microsecond_beg, microsecond_end;
00052 
00053     if (neg == -1)
00054     {
00055       year_beg= ltime2.year;
00056       year_end= ltime1.year;
00057       month_beg= ltime2.month;
00058       month_end= ltime1.month;
00059       day_beg= ltime2.day;
00060       day_end= ltime1.day;
00061       second_beg= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
00062       second_end= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
00063       microsecond_beg= ltime2.second_part;
00064       microsecond_end= ltime1.second_part;
00065     }
00066     else
00067     {
00068       year_beg= ltime1.year;
00069       year_end= ltime2.year;
00070       month_beg= ltime1.month;
00071       month_end= ltime2.month;
00072       day_beg= ltime1.day;
00073       day_end= ltime2.day;
00074       second_beg= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second;
00075       second_end= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second;
00076       microsecond_beg= ltime1.second_part;
00077       microsecond_end= ltime2.second_part;
00078     }
00079 
00080     /* calc years */
00081     years= year_end - year_beg;
00082     if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
00083       years-= 1;
00084 
00085     /* calc months */
00086     months= 12*years;
00087     if (month_end < month_beg || (month_end == month_beg && day_end < day_beg))
00088       months+= 12 - (month_beg - month_end);
00089     else
00090       months+= (month_end - month_beg);
00091 
00092     if (day_end < day_beg)
00093       months-= 1;
00094     else if ((day_end == day_beg) &&
00095        ((second_end < second_beg) ||
00096         (second_end == second_beg && microsecond_end < microsecond_beg)))
00097       months-= 1;
00098   }
00099 
00100   switch (int_type) {
00101   case INTERVAL_YEAR:
00102     return months/12*neg;
00103   case INTERVAL_QUARTER:
00104     return months/3*neg;
00105   case INTERVAL_MONTH:
00106     return months*neg;
00107   case INTERVAL_WEEK:
00108     return seconds/86400L/7L*neg;
00109   case INTERVAL_DAY:
00110     return seconds/86400L*neg;
00111   case INTERVAL_HOUR:
00112     return seconds/3600L*neg;
00113   case INTERVAL_MINUTE:
00114     return seconds/60L*neg;
00115   case INTERVAL_SECOND:
00116     return seconds*neg;
00117   case INTERVAL_MICROSECOND:
00118     /*
00119       In MySQL difference between any two valid datetime values
00120       in microseconds fits into int64_t.
00121     */
00122     return (seconds*1000000L+microseconds)*neg;
00123   default:
00124     break;
00125   }
00126 
00127 null_date:
00128   null_value=1;
00129   return 0;
00130 }
00131 
00132 
00133 void Item_func_timestamp_diff::print(String *str)
00134 {
00135   str->append(func_name());
00136   str->append('(');
00137 
00138   switch (int_type) {
00139   case INTERVAL_YEAR:
00140     str->append(STRING_WITH_LEN("YEAR"));
00141     break;
00142   case INTERVAL_QUARTER:
00143     str->append(STRING_WITH_LEN("QUARTER"));
00144     break;
00145   case INTERVAL_MONTH:
00146     str->append(STRING_WITH_LEN("MONTH"));
00147     break;
00148   case INTERVAL_WEEK:
00149     str->append(STRING_WITH_LEN("WEEK"));
00150     break;
00151   case INTERVAL_DAY:
00152     str->append(STRING_WITH_LEN("DAY"));
00153     break;
00154   case INTERVAL_HOUR:
00155     str->append(STRING_WITH_LEN("HOUR"));
00156     break;
00157   case INTERVAL_MINUTE:
00158     str->append(STRING_WITH_LEN("MINUTE"));
00159     break;
00160   case INTERVAL_SECOND:
00161     str->append(STRING_WITH_LEN("SECOND"));
00162     break;
00163   case INTERVAL_MICROSECOND:
00164     str->append(STRING_WITH_LEN("SECOND_FRAC"));
00165     break;
00166   default:
00167     break;
00168   }
00169 
00170   for (uint32_t i=0 ; i < 2 ; i++)
00171   {
00172     str->append(',');
00173     args[i]->print(str);
00174   }
00175   str->append(')');
00176 }
00177 
00178 } /* namespace drizzled */