Drizzled Public API Documentation

concat.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/str/concat.h>
00023 #include <drizzled/error.h>
00024 #include <drizzled/session.h>
00025 #include <drizzled/system_variables.h>
00026 
00027 #include <algorithm>
00028 
00029 using namespace std;
00030 
00031 namespace drizzled {
00032 
00033 String *Item_func_concat::val_str(String *str)
00034 {
00035   assert(fixed == 1);
00036   String *res,*res2,*use_as_buff;
00037   uint32_t i;
00038   bool is_const= 0;
00039 
00040   null_value=0;
00041   if (!(res=args[0]->val_str(str)))
00042     goto null;
00043   use_as_buff= &tmp_value;
00044   /* Item_subselect in --ps-protocol mode will state it as a non-const */
00045   is_const= args[0]->const_item() || !args[0]->used_tables();
00046   for (i=1 ; i < arg_count ; i++)
00047   {
00048     if (res->length() == 0)
00049     {
00050       if (!(res=args[i]->val_str(str)))
00051         goto null;
00052     }
00053     else
00054     {
00055       if (!(res2=args[i]->val_str(use_as_buff)))
00056         goto null;
00057       if (res2->length() == 0)
00058         continue;
00059       if (res->length()+res2->length() >
00060           session.variables.max_allowed_packet)
00061       {
00062         push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
00063                             ER_WARN_ALLOWED_PACKET_OVERFLOWED,
00064                             ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
00065                             session.variables.max_allowed_packet);
00066         goto null;
00067       }
00068       if (!is_const && res->alloced_length() >= res->length()+res2->length())
00069       {           // Use old buffer
00070         res->append(*res2);
00071       }
00072       else if (str->alloced_length() >= res->length()+res2->length())
00073       {
00074         if (str == res2)
00075           str->replace(0,0,*res);
00076         else
00077         {
00078           str->copy(*res);
00079           str->append(*res2);
00080         }
00081         res= str;
00082         use_as_buff= &tmp_value;
00083       }
00084       else if (res == &tmp_value)
00085       {
00086         res->append(*res2);
00087       }
00088       else if (res2 == &tmp_value)
00089       {           // This can happend only 1 time
00090         tmp_value.replace(0,0,*res);
00091         res= &tmp_value;
00092         use_as_buff=str;      // Put next arg here
00093       }
00094       else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
00095                res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length())
00096       {
00097         /*
00098           This happens really seldom:
00099           In this case res2 is sub string of tmp_value.  We will
00100           now work in place in tmp_value to set it to res | res2
00101         */
00102         /* Chop the last characters in tmp_value that isn't in res2 */
00103         tmp_value.length((uint32_t) (res2->ptr() - tmp_value.ptr()) +
00104                          res2->length());
00105         /* Place res2 at start of tmp_value, remove chars before res2 */
00106         tmp_value.replace(0,(uint32_t) (res2->ptr() - tmp_value.ptr()), *res);
00107         res= &tmp_value;
00108         use_as_buff=str;      // Put next arg here
00109       }
00110       else
00111       {           // Two big const strings
00112         /*
00113           @note We should be prudent in the initial allocation unit -- the
00114           size of the arguments is a function of data distribution, which
00115           can be any. Instead of overcommitting at the first row, we grow
00116           the allocated amount by the factor of 2. This ensures that no
00117           more than 25% of memory will be overcommitted on average.
00118         */
00119 
00120         size_t concat_len= res->length() + res2->length();
00121 
00122         if (tmp_value.alloced_length() < concat_len)
00123         {
00124           if (tmp_value.alloced_length() == 0)
00125           {
00126             tmp_value.alloc(concat_len);
00127           }
00128           else
00129           {
00130             uint32_t new_len= max(tmp_value.alloced_length() * 2, concat_len);
00131 
00132             tmp_value.realloc(new_len);
00133           }
00134         }
00135 
00136         tmp_value.copy(*res);
00137         tmp_value.append(*res2);
00138 
00139         res= &tmp_value;
00140         use_as_buff=str;
00141       }
00142       is_const= 0;
00143     }
00144   }
00145   res->set_charset(collation.collation);
00146   return res;
00147 
00148 null:
00149   null_value=1;
00150   return 0;
00151 }
00152 
00153 
00154 void Item_func_concat::fix_length_and_dec()
00155 {
00156   uint64_t max_result_length= 0;
00157 
00158   if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
00159     return;
00160 
00161   for (uint32_t i=0 ; i < arg_count ; i++)
00162   {
00163     if (args[i]->collation.collation->mbmaxlen != collation.collation->mbmaxlen)
00164       max_result_length+= (args[i]->max_length /
00165                            args[i]->collation.collation->mbmaxlen) *
00166         collation.collation->mbmaxlen;
00167     else
00168       max_result_length+= args[i]->max_length;
00169   }
00170 
00171   if (max_result_length >= MAX_BLOB_WIDTH)
00172   {
00173     max_result_length= MAX_BLOB_WIDTH;
00174     maybe_null= 1;
00175   }
00176   max_length= (ulong) max_result_length;
00177 }
00178 
00179 
00185 String *Item_func_concat_ws::val_str(String *str)
00186 {
00187   assert(fixed == 1);
00188   char tmp_str_buff[10];
00189   String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info),
00190          *sep_str, *res, *res2,*use_as_buff;
00191   uint32_t i;
00192 
00193   null_value=0;
00194   if (!(sep_str= args[0]->val_str(&tmp_sep_str)))
00195     goto null;
00196 
00197   use_as_buff= &tmp_value;
00198   str->length(0);       // QQ; Should be removed
00199   res=str;
00200 
00201   // Skip until non-null argument is found.
00202   // If not, return the empty string
00203   for (i=1; i < arg_count; i++)
00204     if ((res= args[i]->val_str(str)))
00205       break;
00206   if (i ==  arg_count)
00207     return &my_empty_string;
00208 
00209   for (i++; i < arg_count ; i++)
00210   {
00211     if (!(res2= args[i]->val_str(use_as_buff)))
00212       continue;         // Skip NULL
00213 
00214     if (res->length() + sep_str->length() + res2->length() >
00215         session.variables.max_allowed_packet)
00216     {
00217       push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
00218                           ER_WARN_ALLOWED_PACKET_OVERFLOWED,
00219                           ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
00220                           session.variables.max_allowed_packet);
00221       goto null;
00222     }
00223     if (res->alloced_length() >=
00224         res->length() + sep_str->length() + res2->length())
00225     {           // Use old buffer
00226       res->append(*sep_str);      // res->length() > 0 always
00227       res->append(*res2);
00228     }
00229     else if (str->alloced_length() >=
00230              res->length() + sep_str->length() + res2->length())
00231     {
00232       /* We have room in str;  We can't get any errors here */
00233       if (str == res2)
00234       {           // This is quote uncommon!
00235         str->replace(0,0,*sep_str);
00236         str->replace(0,0,*res);
00237       }
00238       else
00239       {
00240         str->copy(*res);
00241         str->append(*sep_str);
00242         str->append(*res2);
00243       }
00244       res=str;
00245       use_as_buff= &tmp_value;
00246     }
00247     else if (res == &tmp_value)
00248     {
00249       res->append(*sep_str);
00250       res->append(*res2);
00251     }
00252     else if (res2 == &tmp_value)
00253     {           // This can happend only 1 time
00254       tmp_value.replace(0,0,*sep_str);
00255       tmp_value.replace(0,0,*res);
00256       res= &tmp_value;
00257       use_as_buff=str;        // Put next arg here
00258     }
00259     else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
00260              res2->ptr() < tmp_value.ptr() + tmp_value.alloced_length())
00261     {
00262       /*
00263         This happens really seldom:
00264         In this case res2 is sub string of tmp_value.  We will
00265         now work in place in tmp_value to set it to res | sep_str | res2
00266       */
00267       /* Chop the last characters in tmp_value that isn't in res2 */
00268       tmp_value.length((uint32_t) (res2->ptr() - tmp_value.ptr()) +
00269                        res2->length());
00270       /* Place res2 at start of tmp_value, remove chars before res2 */
00271       tmp_value.replace(0,(uint32_t) (res2->ptr() - tmp_value.ptr()), *res);
00272       tmp_value.replace(res->length(),0, *sep_str);
00273       res= &tmp_value;
00274       use_as_buff=str;      // Put next arg here
00275     }
00276     else
00277     {           // Two big const strings
00278       /*
00279         @note We should be prudent in the initial allocation unit -- the
00280         size of the arguments is a function of data distribution, which can
00281         be any. Instead of overcommitting at the first row, we grow the
00282         allocated amount by the factor of 2. This ensures that no more than
00283         25% of memory will be overcommitted on average.
00284       */
00285 
00286       size_t concat_len= res->length() + sep_str->length() + res2->length();
00287 
00288       if (tmp_value.alloced_length() < concat_len)
00289       {
00290         if (tmp_value.alloced_length() == 0)
00291         {
00292           tmp_value.alloc(concat_len);
00293         }
00294         else
00295         {
00296           uint32_t new_len= max(tmp_value.alloced_length() * 2, concat_len);
00297 
00298           tmp_value.realloc(new_len);
00299         }
00300       }
00301 
00302       tmp_value.copy(*res);
00303       tmp_value.append(*sep_str);
00304       tmp_value.append(*res2);
00305       res= &tmp_value;
00306       use_as_buff=str;
00307     }
00308   }
00309   res->set_charset(collation.collation);
00310   return res;
00311 
00312 null:
00313   null_value=1;
00314   return 0;
00315 }
00316 
00317 
00318 void Item_func_concat_ws::fix_length_and_dec()
00319 {
00320   uint64_t max_result_length;
00321 
00322   if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
00323     return;
00324 
00325   /*
00326     arg_count cannot be less than 2,
00327     it is done on parser level in sql_yacc.yy
00328     so, (arg_count - 2) is safe here.
00329   */
00330   max_result_length= (uint64_t) args[0]->max_length * (arg_count - 2);
00331   for (uint32_t i=1 ; i < arg_count ; i++)
00332     max_result_length+=args[i]->max_length;
00333 
00334   if (max_result_length >= MAX_BLOB_WIDTH)
00335   {
00336     max_result_length= MAX_BLOB_WIDTH;
00337     maybe_null= 1;
00338   }
00339   max_length= (ulong) max_result_length;
00340 }
00341 
00342 } /* namespace drizzled */