Drizzled Public API Documentation

sql_string.cc
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /* This file is originally from the mysql distribution. Coded by monty */
00017 
00018 #include <config.h>
00019 
00020 #include <drizzled/definitions.h>
00021 #include <drizzled/internal/my_sys.h>
00022 #include <drizzled/internal/m_string.h>
00023 #include <drizzled/memory/root.h>
00024 #include <drizzled/charset.h>
00025 
00026 #include <algorithm>
00027 
00028 #include <drizzled/sql_string.h>
00029 
00030 using namespace std;
00031 
00032 namespace drizzled {
00033 
00034 /*****************************************************************************
00035 ** String functions
00036 *****************************************************************************/
00037 
00038 String::String()
00039   : Ptr(NULL),
00040     str_length(0),
00041     Alloced_length(0),
00042     alloced(false),
00043     str_charset(&my_charset_bin)
00044 { }
00045 
00046 
00047 String::String(size_t length_arg)
00048   : Ptr(NULL),
00049     str_length(0),
00050     Alloced_length(0),
00051     alloced(false),
00052     str_charset(&my_charset_bin)
00053 {
00054   (void) real_alloc(length_arg);
00055 }
00056 
00057 String::String(const char *str, const charset_info_st * const cs)
00058   : Ptr(const_cast<char *>(str)),
00059     str_length(static_cast<size_t>(strlen(str))),
00060     Alloced_length(0),
00061     alloced(false),
00062     str_charset(cs)
00063 { }
00064 
00065 
00066 String::String(const char *str, size_t len, const charset_info_st * const cs)
00067   : Ptr(const_cast<char *>(str)),
00068     str_length(len),
00069     Alloced_length(0),
00070     alloced(false),
00071     str_charset(cs)
00072 { }
00073 
00074 
00075 String::String(char *str, size_t len, const charset_info_st * const cs)
00076   : Ptr(str),
00077     str_length(len),
00078     Alloced_length(len),
00079     alloced(false),
00080     str_charset(cs)
00081 { }
00082 
00083 
00084 String::String(const String &str)
00085   : Ptr(str.Ptr),
00086     str_length(str.str_length),
00087     Alloced_length(str.Alloced_length),
00088     alloced(false),
00089     str_charset(str.str_charset)
00090 { }
00091 
00092 
00093 void *String::operator new(size_t size, memory::Root *mem_root)
00094 {
00095   return mem_root->alloc(size);
00096 }
00097 
00098 String::~String() { free(); }
00099 
00100 void String::real_alloc(size_t arg_length)
00101 {
00102   arg_length=ALIGN_SIZE(arg_length+1);
00103   str_length=0;
00104   if (Alloced_length < arg_length)
00105   {
00106     if (Alloced_length > 0)
00107       free();
00108     Ptr=(char*) malloc(arg_length);
00109     Alloced_length=arg_length;
00110     alloced=1;
00111   }
00112   Ptr[0]=0;
00113 }
00114 
00115 
00116 /*
00117 ** Check that string is big enough. Set string[alloc_length] to 0
00118 ** (for C functions)
00119 */
00120 
00121 void String::realloc(size_t alloc_length)
00122 {
00123   size_t len=ALIGN_SIZE(alloc_length+1);
00124   if (Alloced_length < len)
00125   {
00126     char *new_ptr;
00127     if (alloced)
00128     {
00129       new_ptr= (char*) ::realloc(Ptr,len);
00130       Ptr=new_ptr;
00131       Alloced_length=len;
00132     }
00133     else 
00134     {
00135       new_ptr= (char*) malloc(len);
00136       if (str_length)       // Avoid bugs in memcpy on AIX
00137         memcpy(new_ptr,Ptr,str_length);
00138       new_ptr[str_length]=0;
00139       Ptr=new_ptr;
00140       Alloced_length=len;
00141       alloced=1;
00142     }
00143   }
00144   Ptr[alloc_length]=0;      // This make other funcs shorter
00145 }
00146 
00147 void String::set_int(int64_t num, bool unsigned_flag, const charset_info_st * const cs)
00148 {
00149   size_t l= 20 * cs->mbmaxlen + 1;
00150   alloc(l);
00151   str_length=(size_t) (cs->cset->int64_t10_to_str)(cs, Ptr, l, unsigned_flag ? 10 : -10,num);
00152   str_charset=cs;
00153 }
00154 
00155 void String::set_real(double num,size_t decimals, const charset_info_st * const cs)
00156 {
00157   char buff[FLOATING_POINT_BUFFER];
00158   size_t len;
00159 
00160   str_charset=cs;
00161   if (decimals >= NOT_FIXED_DEC)
00162   {
00163     len= internal::my_gcvt(num, internal::MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
00164     copy(buff, len, cs);
00165     return;
00166   }
00167   len= internal::my_fcvt(num, decimals, buff, NULL);
00168   copy(buff, len, cs);
00169 }
00170 
00171 
00172 void String::copy()
00173 {
00174   if (!alloced)
00175   {
00176     Alloced_length=0;       // Force realloc
00177     realloc(str_length);
00178   }
00179 }
00180 
00181 void String::copy(const String &str)
00182 {
00183   alloc(str.str_length);
00184   str_length=str.str_length;
00185   memmove(Ptr, str.Ptr, str_length);    // May be overlapping
00186   Ptr[str_length]=0;
00187   str_charset= str.str_charset;
00188 }
00189 
00190 void String::copy(const std::string& arg, const charset_info_st* cs) // Allocate new string
00191 {
00192   alloc(arg.size());
00193   str_length= arg.size();
00194   memcpy(Ptr, arg.c_str(), arg.size());
00195   Ptr[arg.size()]= 0;
00196   str_charset= cs;
00197 }
00198 
00199 void String::copy(const char *str,size_t arg_length, const charset_info_st* cs)
00200 {
00201   alloc(arg_length);
00202   if ((str_length=arg_length))
00203     memcpy(Ptr,str,arg_length);
00204   Ptr[arg_length]=0;
00205   str_charset=cs;
00206 }
00207 
00208 /*
00209   Checks that the source string can be just copied to the destination string
00210   without conversion.
00211 
00212   SYNPOSIS
00213 
00214   needs_conversion()
00215   arg_length    Length of string to copy.
00216   from_cs   Character set to copy from
00217   to_cs     Character set to copy to
00218   size_t *offset  Returns number of unaligned characters.
00219 
00220   RETURN
00221    0  No conversion needed
00222    1  Either character set conversion or adding leading  zeros
00223       (e.g. for UCS-2) must be done
00224 
00225   NOTE
00226   to_cs may be NULL for "no conversion" if the system variable
00227   character_set_results is NULL.
00228 */
00229 
00230 bool String::needs_conversion(size_t arg_length, const charset_info_st* from_cs, const charset_info_st* to_cs)
00231 {
00232   if (!to_cs ||
00233       to_cs == &my_charset_bin ||
00234       to_cs == from_cs ||
00235       my_charset_same(from_cs, to_cs) ||
00236       (from_cs == &my_charset_bin && not (arg_length % to_cs->mbminlen)))
00237     return false;
00238   return true;
00239 }
00240 
00241 /*
00242   Set a string to the value of a latin1-string, keeping the original charset
00243 
00244   SYNOPSIS
00245     copy_or_set()
00246     str     String of a simple charset (latin1)
00247     arg_length    Length of string
00248 
00249   IMPLEMENTATION
00250     If string object is of a simple character set, set it to point to the
00251     given string.
00252     If not, make a copy and convert it to the new character set.
00253 
00254   RETURN
00255     0 ok
00256     1 Could not allocate result buffer
00257 
00258 */
00259 
00260 void String::set_ascii(const char *str, size_t arg_length)
00261 {
00262   if (str_charset->mbminlen == 1)
00263   {
00264     set(str, arg_length, str_charset);
00265     return;
00266   }
00267   copy(str, arg_length, str_charset);
00268 }
00269 
00270 
00271 /*
00272   Append an ASCII string to the a string of the current character set
00273 */
00274 
00275 void String::append(const char *s,size_t arg_length)
00276 {
00277   if (arg_length == 0)
00278     return;
00279 
00280   /*
00281     For an ASCII compatinble string we can just append.
00282   */
00283   realloc(str_length + arg_length);
00284   memcpy(Ptr + str_length, s, arg_length);
00285   str_length+= arg_length;
00286 }
00287 
00288 /*
00289   Append a 0-terminated ASCII string
00290 */
00291 
00292 void String::append(const char *s)
00293 {
00294   append(s, strlen(s));
00295 }
00296 
00297 void String::append(str_ref s)
00298 {
00299   append(s.data(), s.size());
00300 }
00301 
00302 void String::append_with_prefill(const char *s,size_t arg_length, size_t full_length, char fill_char)
00303 {
00304   int t_length= arg_length > full_length ? arg_length : full_length;
00305 
00306   realloc(str_length + t_length);
00307   t_length= full_length - arg_length;
00308   if (t_length > 0)
00309   {
00310     memset(Ptr+str_length, fill_char, t_length);
00311     str_length=str_length + t_length;
00312   }
00313   append(s, arg_length);
00314 }
00315 
00316 size_t String::numchars() const
00317 {
00318   return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
00319 }
00320 
00321 int String::charpos(int i,size_t offset) const
00322 {
00323   return i <= 0 ? i : str_charset->cset->charpos(str_charset, Ptr + offset, Ptr + str_length, i);
00324 }
00325 
00326 int String::strstr(const String &s, size_t offset)
00327 {
00328   if (s.length() + offset <= str_length)
00329   {
00330     if (!s.length())
00331       return ((int) offset);  // Empty string is always found
00332 
00333     const char *str = Ptr+offset;
00334     const char *search=s.ptr();
00335     const char *last=Ptr+str_length-s.length()+1;
00336     const char *search_end=s.ptr()+s.length();
00337 skip:
00338     while (str != last)
00339     {
00340       if (*str++ == *search)
00341       {
00342         const char* i= str; 
00343         const char* j= search + 1;
00344         while (j != search_end)
00345           if (*i++ != *j++) goto skip;
00346         return (int) (str - Ptr) - 1;
00347       }
00348     }
00349   }
00350   return -1;
00351 }
00352 
00353 /*
00354 ** Search string from end. Offset is offset to the end of string
00355 */
00356 
00357 int String::strrstr(const String &s,size_t offset)
00358 {
00359   if (s.length() <= offset && offset <= str_length)
00360   {
00361     if (!s.length())
00362       return offset;        // Empty string is always found
00363     const char *str = Ptr+offset-1;
00364     const char *search=s.ptr()+s.length()-1;
00365 
00366     const char *last=Ptr+s.length()-2;
00367     const char *search_end=s.ptr()-1;
00368 skip:
00369     while (str != last)
00370     {
00371       if (*str-- == *search)
00372       {
00373         const char* i= str; 
00374         const char* j= search-1;
00375         while (j != search_end)
00376           if (*i-- != *j--) goto skip;
00377         return (int) (i-Ptr) + 1;
00378       }
00379     }
00380   }
00381   return -1;
00382 }
00383 
00384 /*
00385   Replace substring with string
00386   If wrong parameter or not enough memory, do nothing
00387 */
00388 
00389 void String::replace(size_t offset,size_t arg_length,const String &to)
00390 {
00391   replace(offset,arg_length,to.ptr(),to.length());
00392 }
00393 
00394 void String::replace(size_t offset,size_t arg_length,
00395                      const char *to, size_t to_length)
00396 {
00397   long diff = (long) to_length-(long) arg_length;
00398   if (offset+arg_length <= str_length)
00399   {
00400     if (diff < 0)
00401     {
00402       if (to_length)
00403   memcpy(Ptr+offset,to,to_length);
00404       memmove(Ptr+offset+to_length, Ptr+offset+arg_length,
00405               str_length-offset-arg_length);
00406     }
00407     else
00408     {
00409       if (diff)
00410       {
00411   realloc(str_length+(size_t) diff);
00412   internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
00413                             (unsigned char*) Ptr+str_length,
00414                             str_length-offset-arg_length);
00415       }
00416       if (to_length)
00417   memcpy(Ptr+offset,to,to_length);
00418     }
00419     str_length+=(size_t) diff;
00420   }
00421 }
00422 
00423 
00424 
00425 /*
00426   Compare strings according to collation, without end space.
00427 
00428   SYNOPSIS
00429     sortcmp()
00430     s   First string
00431     t   Second string
00432     cs    Collation
00433 
00434   NOTE:
00435     Normally this is case sensitive comparison
00436 
00437   RETURN
00438   < 0 s < t
00439   0 s == t
00440   > 0 s > t
00441 */
00442 
00443 
00444 int sortcmp(const String *s,const String *t, const charset_info_st * const cs)
00445 {
00446  return cs->coll->strnncollsp(cs,
00447                               (unsigned char *) s->ptr(),s->length(),
00448                               (unsigned char *) t->ptr(),t->length(), 0);
00449 }
00450 
00451 
00452 /*
00453   Compare strings byte by byte. End spaces are also compared.
00454 
00455   SYNOPSIS
00456     stringcmp()
00457     s   First string
00458     t   Second string
00459 
00460   NOTE:
00461     Strings are compared as a stream of unsigned chars
00462 
00463   RETURN
00464   < 0 s < t
00465   0 s == t
00466   > 0 s > t
00467 */
00468 
00469 
00470 int stringcmp(const String *s,const String *t)
00471 {
00472   size_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
00473   int cmp= memcmp(s->ptr(), t->ptr(), len);
00474   return (cmp) ? cmp : (int) (s_len - t_len);
00475 }
00476 
00477 
00478 String *copy_if_not_alloced(String *to,String *from,size_t from_length)
00479 {
00480   if (from->Alloced_length >= from_length)
00481     return from;
00482   if (from->alloced || !to || from == to)
00483   {
00484     (void) from->realloc(from_length);
00485     return from;
00486   }
00487   to->realloc(from_length);
00488   if ((to->str_length= min(from->str_length,from_length)))
00489     memcpy(to->Ptr,from->Ptr,to->str_length);
00490   to->str_charset=from->str_charset;
00491   return to;
00492 }
00493 
00494 
00495 /****************************************************************************
00496   Help functions
00497 ****************************************************************************/
00498 
00499 /*
00500   copy a string,
00501   with optional character set conversion,
00502   with optional left padding (for binary -> UCS2 conversion)
00503 
00504   SYNOPSIS
00505     well_formed_copy_nchars()
00506     to           Store result here
00507     to_length                Maxinum length of "to" string
00508     to_cs        Character set of "to" string
00509     from         Copy from here
00510     from_length        Length of from string
00511     from_cs        From character set
00512     nchars                   Copy not more that nchars characters
00513     well_formed_error_pos    Return position when "from" is not well formed
00514                              or NULL otherwise.
00515     cannot_convert_error_pos Return position where a not convertable
00516                              character met, or NULL otherwise.
00517     from_end_pos             Return position where scanning of "from"
00518                              string stopped.
00519   NOTES
00520 
00521   RETURN
00522     length of bytes copied to 'to'
00523 */
00524 
00525 
00526 size_t
00527 well_formed_copy_nchars(const charset_info_st * const to_cs,
00528                         char *to, size_t to_length,
00529                         const charset_info_st * const from_cs,
00530                         const char *from, size_t from_length,
00531                         size_t nchars,
00532                         const char **well_formed_error_pos,
00533                         const char **cannot_convert_error_pos,
00534                         const char **from_end_pos)
00535 {
00536   size_t res;
00537 
00538   assert((to_cs == &my_charset_bin) ||
00539          (from_cs == &my_charset_bin) ||
00540          (to_cs == from_cs) ||
00541          my_charset_same(from_cs, to_cs));
00542 
00543   if (to_length < to_cs->mbminlen || !nchars)
00544   {
00545     *from_end_pos= from;
00546     *cannot_convert_error_pos= NULL;
00547     *well_formed_error_pos= NULL;
00548     return 0;
00549   }
00550 
00551   if (to_cs == &my_charset_bin)
00552   {
00553     res= min(min(nchars, to_length), from_length);
00554     memmove(to, from, res);
00555     *from_end_pos= from + res;
00556     *well_formed_error_pos= NULL;
00557     *cannot_convert_error_pos= NULL;
00558   }
00559   else
00560   {
00561     int well_formed_error;
00562     size_t from_offset;
00563 
00564     if ((from_offset= (from_length % to_cs->mbminlen)) &&
00565         (from_cs == &my_charset_bin))
00566     {
00567       /*
00568         Copying from BINARY to UCS2 needs to prepend zeros sometimes:
00569         INSERT INTO t1 (ucs2_column) VALUES (0x01);
00570         0x01 -> 0x0001
00571       */
00572       size_t pad_length= to_cs->mbminlen - from_offset;
00573       memset(to, 0, pad_length);
00574       memmove(to + pad_length, from, from_offset);
00575       nchars--;
00576       from+= from_offset;
00577       from_length-= from_offset;
00578       to+= to_cs->mbminlen;
00579       to_length-= to_cs->mbminlen;
00580     }
00581 
00582     set_if_smaller(from_length, to_length);
00583     res= to_cs->cset->well_formed_len(*to_cs, str_ref(from, from_length), nchars, &well_formed_error);
00584     memmove(to, from, res);
00585     *from_end_pos= from + res;
00586     *well_formed_error_pos= well_formed_error ? from + res : NULL;
00587     *cannot_convert_error_pos= NULL;
00588     if (from_offset)
00589       res+= to_cs->mbminlen;
00590   }
00591 
00592   return res;
00593 }
00594 
00595 void String::print(String& str) const
00596 {
00597   const char* last= Ptr + str_length;
00598   for (const char* st= Ptr; st < last; st++)
00599   {
00600     unsigned char c= *st;
00601     switch (c)
00602     {
00603     case '\\':
00604       str.append("\\\\", sizeof("\\\\")-1);
00605       break;
00606     case '\0':
00607       str.append("\\0", sizeof("\\0")-1);
00608       break;
00609     case '\'':
00610       str.append("\\'", sizeof("\\'")-1);
00611       break;
00612     case '\n':
00613       str.append("\\n", sizeof("\\n")-1);
00614       break;
00615     case '\r':
00616       str.append("\\r", sizeof("\\r")-1);
00617       break;
00618     case '\032': // Ctrl-Z
00619       str.append("\\Z", sizeof("\\Z")-1);
00620       break;
00621     default:
00622       str.append(c);
00623     }
00624   }
00625 }
00626 
00627 /*
00628   Quote the given identifier.
00629   If the given identifier is empty, it will be quoted.
00630 
00631   SYNOPSIS
00632   append_identifier()
00633   name                  the identifier to be appended
00634   name_length           length of the appending identifier
00635 */
00636 
00637 /* Factor the extern out */
00638 extern const charset_info_st *system_charset_info;
00639 
00640 void String::append_identifier(const char *name, size_t in_length)
00641 {
00642   // The identifier must be quoted as it includes a quote character or it's a keyword
00643 
00644   reserve(in_length * 2 + 2);
00645   const char quote_char= '`';
00646   append(&quote_char, 1);
00647 
00648   for (const char* name_end= name+in_length ; name < name_end ; name+= in_length)
00649   {
00650     unsigned char chr= (unsigned char) *name;
00651     in_length= my_mbcharlen(system_charset_info, chr);
00652     /*
00653       my_mbcharlen can return 0 on a wrong multibyte
00654       sequence. It is possible when upgrading from 4.0,
00655       and identifier contains some accented characters.
00656       The manual says it does not work. So we'll just
00657       change length to 1 not to hang in the endless loop.
00658     */
00659     if (!in_length)
00660       in_length= 1;
00661     if (in_length == 1 && chr == (unsigned char) quote_char)
00662       append(&quote_char, 1);
00663     append(name, in_length);
00664   }
00665   append(&quote_char, 1);
00666 }
00667 
00668 void String::append_identifier(str_ref v)
00669 {
00670   append_identifier(v.data(), v.size());
00671 }
00672 
00673 bool check_if_only_end_space(const charset_info_st * const cs, char *str, char *end)
00674 {
00675   return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
00676 }
00677 
00678 std::ostream& operator<<(std::ostream& output, const String &str)
00679 {
00680   output << "String:(";
00681   output <<  const_cast<String&>(str).c_str();
00682   output << ", ";
00683   output << str.length();
00684   output << ")";
00685 
00686   return output;  // for multiple << operators.
00687 }
00688 
00689 } /* namespace drizzled */
00690 
00691 bool operator==(const drizzled::String &s1, const drizzled::String &s2)
00692 {
00693   return stringcmp(&s1,&s2) == 0;
00694 }
00695 
00696 bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
00697 {
00698   return !(s1 == s2);
00699 }
00700