Drizzled Public API Documentation

min_max.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/min_max.h>
00023 #include <drizzled/item/cmpfunc.h>
00024 #include <drizzled/session.h>
00025 
00026 namespace drizzled
00027 {
00028 
00029 void Item_func_min_max::fix_length_and_dec()
00030 {
00031   int max_int_part=0;
00032   bool datetime_found= false;
00033   decimals=0;
00034   max_length=0;
00035   maybe_null=0;
00036   cmp_type=args[0]->result_type();
00037 
00038   for (uint32_t i=0 ; i < arg_count ; i++)
00039   {
00040     set_if_bigger(max_length, args[i]->max_length);
00041     set_if_bigger(decimals, args[i]->decimals);
00042     set_if_bigger(max_int_part, args[i]->decimal_int_part());
00043     if (args[i]->maybe_null)
00044       maybe_null=1;
00045     cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
00046     if (args[i]->result_type() != ROW_RESULT && args[i]->is_datetime())
00047     {
00048       datetime_found= true;
00049       if (!datetime_item || args[i]->field_type() == DRIZZLE_TYPE_DATETIME)
00050         datetime_item= args[i];
00051     }
00052   }
00053   if (cmp_type == STRING_RESULT)
00054   {
00055     agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
00056     if (datetime_found)
00057     {
00058       session= getSessionPtr();
00059       compare_as_dates= true;
00060     }
00061   }
00062   else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
00063     max_length= class_decimal_precision_to_length(max_int_part+decimals, decimals,
00064                                             unsigned_flag);
00065   cached_field_type= agg_field_type(args, arg_count);
00066 }
00067 
00068 
00069 /*
00070   Compare item arguments in the DATETIME context.
00071 
00072   SYNOPSIS
00073     cmp_datetimes()
00074     value [out]   found least/greatest DATE/DATETIME value
00075 
00076   DESCRIPTION
00077     Compare item arguments as DATETIME values and return the index of the
00078     least/greatest argument in the arguments array.
00079     The correct integer DATE/DATETIME value of the found argument is
00080     stored to the value pointer, if latter is provided.
00081 
00082   RETURN
00083    0  If one of arguments is NULL or there was a execution error
00084    #  index of the least/greatest argument
00085 */
00086 
00087 uint32_t Item_func_min_max::cmp_datetimes(uint64_t *value)
00088 {
00089   uint64_t min_max= 0;
00090   uint32_t min_max_idx= 0;
00091 
00092   for (uint32_t i=0; i < arg_count ; i++)
00093   {
00094     Item **arg= args + i;
00095     bool is_null_unused;
00096     uint64_t res= get_datetime_value(session, &arg, 0, datetime_item,
00097                                      &is_null_unused);
00098 
00099     /* Check if we need to stop (because of error or KILL)  and stop the loop */
00100     if (session->is_error())
00101     {
00102       null_value= 1;
00103       return 0;
00104     }
00105 
00106     if ((null_value= args[i]->null_value))
00107       return 0;
00108     if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
00109     {
00110       min_max= res;
00111       min_max_idx= i;
00112     }
00113   }
00114   if (value)
00115   {
00116     *value= min_max;
00117     if (datetime_item->field_type() == DRIZZLE_TYPE_DATE)
00118       *value/= 1000000L;
00119   }
00120   return min_max_idx;
00121 }
00122 
00123 
00124 String *Item_func_min_max::val_str(String *str)
00125 {
00126   assert(fixed == 1);
00127   if (compare_as_dates)
00128   {
00129     String *str_res;
00130     uint32_t min_max_idx= cmp_datetimes(NULL);
00131     if (null_value)
00132       return 0;
00133     str_res= args[min_max_idx]->val_str(str);
00134     if (args[min_max_idx]->null_value)
00135     {
00136       // check if the call to val_str() above returns a NULL value
00137       null_value= 1;
00138       return NULL;
00139     }
00140     str_res->set_charset(collation.collation);
00141     return str_res;
00142   }
00143   switch (cmp_type) {
00144   case INT_RESULT:
00145     {
00146       int64_t nr=val_int();
00147       if (null_value)
00148         return 0;
00149       str->set_int(nr, unsigned_flag, &my_charset_bin);
00150       return str;
00151     }
00152 
00153   case DECIMAL_RESULT:
00154     {
00155       type::Decimal dec_buf, *dec_val= val_decimal(&dec_buf);
00156       if (null_value)
00157         return 0;
00158       class_decimal2string(dec_val, 0, str);
00159       return str;
00160     }
00161 
00162   case REAL_RESULT:
00163     {
00164       double nr= val_real();
00165       if (null_value)
00166         return 0;
00167       str->set_real(nr,decimals,&my_charset_bin);
00168       return str;
00169     }
00170 
00171   case STRING_RESULT:
00172     {
00173       String *res= NULL;
00174 
00175       for (uint32_t i=0; i < arg_count ; i++)
00176       {
00177         if (i == 0)
00178           res=args[i]->val_str(str);
00179         else
00180         {
00181           String *res2;
00182           res2= args[i]->val_str(res == str ? &tmp_value : str);
00183           if (res2)
00184           {
00185             int cmp= sortcmp(res,res2,collation.collation);
00186             if ((cmp_sign < 0 ? cmp : -cmp) < 0)
00187               res=res2;
00188           }
00189         }
00190         if ((null_value= args[i]->null_value))
00191           return 0;
00192       }
00193       res->set_charset(collation.collation);
00194       return res;
00195     }
00196 
00197   case ROW_RESULT:
00198     // This case should never be chosen
00199     assert(0);
00200     return 0;
00201   }
00202 
00203   return 0;         // Keep compiler happy
00204 }
00205 
00206 
00207 double Item_func_min_max::val_real()
00208 {
00209   assert(fixed == 1);
00210   double value=0.0;
00211   if (compare_as_dates)
00212   {
00213     uint64_t result= 0;
00214     (void)cmp_datetimes(&result);
00215     return (double)result;
00216   }
00217   for (uint32_t i=0; i < arg_count ; i++)
00218   {
00219     if (i == 0)
00220       value= args[i]->val_real();
00221     else
00222     {
00223       double tmp= args[i]->val_real();
00224       if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
00225   value=tmp;
00226     }
00227     if ((null_value= args[i]->null_value))
00228       break;
00229   }
00230   return value;
00231 }
00232 
00233 
00234 int64_t Item_func_min_max::val_int()
00235 {
00236   assert(fixed == 1);
00237   int64_t value=0;
00238   if (compare_as_dates)
00239   {
00240     uint64_t result= 0;
00241     (void)cmp_datetimes(&result);
00242     return (int64_t)result;
00243   }
00244   for (uint32_t i=0; i < arg_count ; i++)
00245   {
00246     if (i == 0)
00247       value=args[i]->val_int();
00248     else
00249     {
00250       int64_t tmp=args[i]->val_int();
00251       if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
00252   value=tmp;
00253     }
00254     if ((null_value= args[i]->null_value))
00255       break;
00256   }
00257   return value;
00258 }
00259 
00260 
00261 type::Decimal *Item_func_min_max::val_decimal(type::Decimal *dec)
00262 {
00263   assert(fixed == 1);
00264   type::Decimal tmp_buf, *tmp, *res= NULL;
00265 
00266   if (compare_as_dates)
00267   {
00268     uint64_t value= 0;
00269     (void)cmp_datetimes(&value);
00270     uint64_t2decimal(value, dec);
00271     return dec;
00272   }
00273   for (uint32_t i=0; i < arg_count ; i++)
00274   {
00275     if (i == 0)
00276       res= args[i]->val_decimal(dec);
00277     else
00278     {
00279       tmp= args[i]->val_decimal(&tmp_buf);      // Zero if NULL
00280       if (tmp && (class_decimal_cmp(tmp, res) * cmp_sign) < 0)
00281       {
00282         if (tmp == &tmp_buf)
00283         {
00284           /* Move value out of tmp_buf as this will be reused on next loop */
00285           class_decimal2decimal(tmp, dec);
00286           res= dec;
00287         }
00288         else
00289           res= tmp;
00290       }
00291     }
00292     if ((null_value= args[i]->null_value))
00293     {
00294       res= 0;
00295       break;
00296     }
00297   }
00298   return res;
00299 }
00300 
00301 } /* namespace drizzled */