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