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/internal/my_sys.h>
00021 #include <drizzled/internal/m_string.h>
00022 #include <drizzled/charset.h>
00023 #include <drizzled/global_charset_info.h>
00024 
00025 #include <algorithm>
00026 
00027 #include <drizzled/sql_string.h>
00028 
00029 using namespace std;
00030 
00031 namespace drizzled
00032 {
00033 
00034 // Converstion functions to and from std::string.
00035 
00036 std::string String_to_std_string(String const& s)
00037 {
00038    return std::string(s.ptr(), s.length());
00039 }
00040 
00041 String* set_String_from_std_string(String* s, std::string const& cs)
00042 {
00043    s->set_ascii(cs.c_str(), cs.length());
00044    s->copy();
00045    return s;
00046 }
00047 
00048 /*****************************************************************************
00049 ** String functions
00050 *****************************************************************************/
00051 
00052 String::String()
00053   : Ptr(NULL),
00054     str_length(0),
00055     Alloced_length(0),
00056     alloced(false),
00057     str_charset(&my_charset_bin)
00058 { }
00059 
00060 
00061 String::String(size_t length_arg)
00062   : Ptr(NULL),
00063     str_length(0),
00064     Alloced_length(0),
00065     alloced(false),
00066     str_charset(&my_charset_bin)
00067 {
00068   (void) real_alloc(length_arg);
00069 }
00070 
00071 String::String(const char *str, const CHARSET_INFO * const cs)
00072   : Ptr(const_cast<char *>(str)),
00073     str_length(static_cast<size_t>(strlen(str))),
00074     Alloced_length(0),
00075     alloced(false),
00076     str_charset(cs)
00077 { }
00078 
00079 
00080 String::String(const char *str, size_t len, const CHARSET_INFO * const cs)
00081   : Ptr(const_cast<char *>(str)),
00082     str_length(len),
00083     Alloced_length(0),
00084     alloced(false),
00085     str_charset(cs)
00086 { }
00087 
00088 
00089 String::String(char *str, size_t len, const CHARSET_INFO * const cs)
00090   : Ptr(str),
00091     str_length(len),
00092     Alloced_length(len),
00093     alloced(false),
00094     str_charset(cs)
00095 { }
00096 
00097 
00098 String::String(const String &str)
00099   : Ptr(str.Ptr),
00100     str_length(str.str_length),
00101     Alloced_length(str.Alloced_length),
00102     alloced(false),
00103     str_charset(str.str_charset)
00104 { }
00105 
00106 
00107 void *String::operator new(size_t size, memory::Root *mem_root)
00108 {
00109   return mem_root->alloc_root(static_cast<size_t>(size));
00110 }
00111 
00112 String::~String() { free(); }
00113 
00114 bool String::real_alloc(size_t arg_length)
00115 {
00116   arg_length=ALIGN_SIZE(arg_length+1);
00117   str_length=0;
00118   if (Alloced_length < arg_length)
00119   {
00120     if (Alloced_length > 0)
00121       free();
00122     if (!(Ptr=(char*) malloc(arg_length)))
00123       return true;
00124     Alloced_length=arg_length;
00125     alloced=1;
00126   }
00127   Ptr[0]=0;
00128   return false;
00129 }
00130 
00131 
00132 /*
00133 ** Check that string is big enough. Set string[alloc_length] to 0
00134 ** (for C functions)
00135 */
00136 
00137 bool String::realloc(size_t alloc_length)
00138 {
00139   size_t len=ALIGN_SIZE(alloc_length+1);
00140   if (Alloced_length < len)
00141   {
00142     char *new_ptr;
00143     if (alloced)
00144     {
00145       if ((new_ptr= (char*) ::realloc(Ptr,len)))
00146       {
00147   Ptr=new_ptr;
00148   Alloced_length=len;
00149       }
00150       else
00151   return true;        // Signal error
00152     }
00153     else if ((new_ptr= (char*) malloc(len)))
00154     {
00155       if (str_length)       // Avoid bugs in memcpy on AIX
00156   memcpy(new_ptr,Ptr,str_length);
00157       new_ptr[str_length]=0;
00158       Ptr=new_ptr;
00159       Alloced_length=len;
00160       alloced=1;
00161     }
00162     else
00163       return true;      // Signal error
00164   }
00165   Ptr[alloc_length]=0;      // This make other funcs shorter
00166   return false;
00167 }
00168 
00169 bool String::set_int(int64_t num, bool unsigned_flag, const CHARSET_INFO * const cs)
00170 {
00171   size_t l=20*cs->mbmaxlen+1;
00172   int base= unsigned_flag ? 10 : -10;
00173 
00174   if (alloc(l))
00175     return true;
00176   str_length=(size_t) (cs->cset->int64_t10_to_str)(cs,Ptr,l,base,num);
00177   str_charset=cs;
00178   return false;
00179 }
00180 
00181 bool String::set_real(double num,size_t decimals, const CHARSET_INFO * const cs)
00182 {
00183   char buff[FLOATING_POINT_BUFFER];
00184   size_t dummy_errors;
00185   size_t len;
00186 
00187   str_charset=cs;
00188   if (decimals >= NOT_FIXED_DEC)
00189   {
00190     len= internal::my_gcvt(num,
00191                            internal::MY_GCVT_ARG_DOUBLE,
00192                            sizeof(buff) - 1, buff, NULL);
00193     return copy(buff, len, &my_charset_utf8_general_ci, cs, &dummy_errors);
00194   }
00195   len= internal::my_fcvt(num, decimals, buff, NULL);
00196   return copy(buff, (size_t) len, &my_charset_utf8_general_ci, cs,
00197               &dummy_errors);
00198 }
00199 
00200 
00201 bool String::copy()
00202 {
00203   if (!alloced)
00204   {
00205     Alloced_length=0;       // Force realloc
00206     return realloc(str_length);
00207   }
00208   return false;
00209 }
00210 
00211 bool String::copy(const String &str)
00212 {
00213   if (alloc(str.str_length))
00214     return true;
00215   str_length=str.str_length;
00216   memmove(Ptr, str.Ptr, str_length);    // May be overlapping
00217   Ptr[str_length]=0;
00218   str_charset=str.str_charset;
00219   return false;
00220 }
00221 
00222 bool String::copy(const std::string& arg, const CHARSET_INFO * const cs)  // Allocate new string
00223 {
00224   if (alloc(arg.size()))
00225     return true;
00226 
00227   if ((str_length= arg.size()))
00228     memcpy(Ptr, arg.c_str(), arg.size());
00229 
00230   Ptr[arg.size()]= 0;
00231   str_charset= cs;
00232 
00233   return false;
00234 }
00235 
00236 bool String::copy(const char *str,size_t arg_length, const CHARSET_INFO * const cs)
00237 {
00238   if (alloc(arg_length))
00239     return true;
00240   if ((str_length=arg_length))
00241     memcpy(Ptr,str,arg_length);
00242   Ptr[arg_length]=0;
00243   str_charset=cs;
00244   return false;
00245 }
00246 
00247 /*
00248   Checks that the source string can be just copied to the destination string
00249   without conversion.
00250 
00251   SYNPOSIS
00252 
00253   needs_conversion()
00254   arg_length    Length of string to copy.
00255   from_cs   Character set to copy from
00256   to_cs     Character set to copy to
00257   size_t *offset  Returns number of unaligned characters.
00258 
00259   RETURN
00260    0  No conversion needed
00261    1  Either character set conversion or adding leading  zeros
00262       (e.g. for UCS-2) must be done
00263 
00264   NOTE
00265   to_cs may be NULL for "no conversion" if the system variable
00266   character_set_results is NULL.
00267 */
00268 
00269 bool String::needs_conversion(size_t arg_length,
00270             const CHARSET_INFO * const from_cs,
00271             const CHARSET_INFO * const to_cs,
00272             size_t *offset)
00273 {
00274   *offset= 0;
00275   if (!to_cs ||
00276       (to_cs == &my_charset_bin) ||
00277       (to_cs == from_cs) ||
00278       my_charset_same(from_cs, to_cs) ||
00279       ((from_cs == &my_charset_bin) &&
00280        (!(*offset=(arg_length % to_cs->mbminlen)))))
00281     return false;
00282   return true;
00283 }
00284 
00285 
00286 
00287 
00288 bool String::set_or_copy_aligned(const char *str,size_t arg_length,
00289                                  const CHARSET_INFO * const cs)
00290 {
00291   /* How many bytes are in incomplete character */
00292   size_t offset= (arg_length % cs->mbminlen);
00293 
00294   assert(!offset); /* All characters are complete, just copy */
00295 
00296   set(str, arg_length, cs);
00297   return false;
00298 }
00299 
00300   /* Copy with charset conversion */
00301 
00302 bool String::copy(const char *str, size_t arg_length,
00303               const CHARSET_INFO * const,
00304           const CHARSET_INFO * const to_cs, size_t *errors)
00305 {
00306   *errors= 0;
00307   return copy(str, arg_length, to_cs);
00308 }
00309 
00310 
00311 /*
00312   Set a string to the value of a latin1-string, keeping the original charset
00313 
00314   SYNOPSIS
00315     copy_or_set()
00316     str     String of a simple charset (latin1)
00317     arg_length    Length of string
00318 
00319   IMPLEMENTATION
00320     If string object is of a simple character set, set it to point to the
00321     given string.
00322     If not, make a copy and convert it to the new character set.
00323 
00324   RETURN
00325     0 ok
00326     1 Could not allocate result buffer
00327 
00328 */
00329 
00330 bool String::set_ascii(const char *str, size_t arg_length)
00331 {
00332   if (str_charset->mbminlen == 1)
00333   {
00334     set(str, arg_length, str_charset);
00335     return 0;
00336   }
00337   size_t dummy_errors;
00338   return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
00339 }
00340 
00341 bool String::append(const String &s)
00342 {
00343   if (s.length())
00344   {
00345     if (realloc(str_length+s.length()))
00346       return true;
00347     memcpy(Ptr+str_length,s.ptr(),s.length());
00348     str_length+=s.length();
00349   }
00350   return false;
00351 }
00352 
00353 
00354 /*
00355   Append an ASCII string to the a string of the current character set
00356 */
00357 
00358 bool String::append(const char *s,size_t arg_length)
00359 {
00360   if (!arg_length)
00361     return false;
00362 
00363   /*
00364     For an ASCII compatinble string we can just append.
00365   */
00366   if (realloc(str_length+arg_length))
00367     return true;
00368   memcpy(Ptr+str_length,s,arg_length);
00369   str_length+=arg_length;
00370   return false;
00371 }
00372 
00373 
00374 /*
00375   Append a 0-terminated ASCII string
00376 */
00377 
00378 bool String::append(const char *s)
00379 {
00380   return append(s, strlen(s));
00381 }
00382 
00383 
00384 /*
00385   Append a string in the given charset to the string
00386   with character set recoding
00387 */
00388 
00389 bool String::append(const char *s,size_t arg_length, const CHARSET_INFO * const)
00390 {
00391   if (realloc(str_length + arg_length))
00392     return true;
00393   memcpy(Ptr + str_length, s, arg_length);
00394   str_length+= arg_length;
00395 
00396   return false;
00397 }
00398 
00399 
00400 bool String::append_with_prefill(const char *s,size_t arg_length,
00401      size_t full_length, char fill_char)
00402 {
00403   int t_length= arg_length > full_length ? arg_length : full_length;
00404 
00405   if (realloc(str_length + t_length))
00406     return true;
00407   t_length= full_length - arg_length;
00408   if (t_length > 0)
00409   {
00410     memset(Ptr+str_length, fill_char, t_length);
00411     str_length=str_length + t_length;
00412   }
00413   append(s, arg_length);
00414   return false;
00415 }
00416 
00417 size_t String::numchars()
00418 {
00419   return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
00420 }
00421 
00422 int String::charpos(int i,size_t offset)
00423 {
00424   if (i <= 0)
00425     return i;
00426   return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
00427 }
00428 
00429 int String::strstr(const String &s,size_t offset)
00430 {
00431   if (s.length()+offset <= str_length)
00432   {
00433     if (!s.length())
00434       return ((int) offset);  // Empty string is always found
00435 
00436     const char *str = Ptr+offset;
00437     const char *search=s.ptr();
00438     const char *end=Ptr+str_length-s.length()+1;
00439     const char *search_end=s.ptr()+s.length();
00440 skip:
00441     while (str != end)
00442     {
00443       if (*str++ == *search)
00444       {
00445   char *i,*j;
00446   i=(char*) str; j=(char*) search+1;
00447   while (j != search_end)
00448     if (*i++ != *j++) goto skip;
00449   return (int) (str-Ptr) -1;
00450       }
00451     }
00452   }
00453   return -1;
00454 }
00455 
00456 /*
00457 ** Search string from end. Offset is offset to the end of string
00458 */
00459 
00460 int String::strrstr(const String &s,size_t offset)
00461 {
00462   if (s.length() <= offset && offset <= str_length)
00463   {
00464     if (!s.length())
00465       return offset;        // Empty string is always found
00466     const char *str = Ptr+offset-1;
00467     const char *search=s.ptr()+s.length()-1;
00468 
00469     const char *end=Ptr+s.length()-2;
00470     const char *search_end=s.ptr()-1;
00471 skip:
00472     while (str != end)
00473     {
00474       if (*str-- == *search)
00475       {
00476   char *i,*j;
00477   i=(char*) str; j=(char*) search-1;
00478   while (j != search_end)
00479     if (*i-- != *j--) goto skip;
00480   return (int) (i-Ptr) +1;
00481       }
00482     }
00483   }
00484   return -1;
00485 }
00486 
00487 /*
00488   Replace substring with string
00489   If wrong parameter or not enough memory, do nothing
00490 */
00491 
00492 bool String::replace(size_t offset,size_t arg_length,const String &to)
00493 {
00494   return replace(offset,arg_length,to.ptr(),to.length());
00495 }
00496 
00497 bool String::replace(size_t offset,size_t arg_length,
00498                      const char *to, size_t to_length)
00499 {
00500   long diff = (long) to_length-(long) arg_length;
00501   if (offset+arg_length <= str_length)
00502   {
00503     if (diff < 0)
00504     {
00505       if (to_length)
00506   memcpy(Ptr+offset,to,to_length);
00507       memmove(Ptr+offset+to_length, Ptr+offset+arg_length,
00508               str_length-offset-arg_length);
00509     }
00510     else
00511     {
00512       if (diff)
00513       {
00514   if (realloc(str_length+(size_t) diff))
00515     return true;
00516   internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
00517                             (unsigned char*) Ptr+str_length,
00518                             str_length-offset-arg_length);
00519       }
00520       if (to_length)
00521   memcpy(Ptr+offset,to,to_length);
00522     }
00523     str_length+=(size_t) diff;
00524   }
00525   return false;
00526 }
00527 
00528 
00529 
00530 /*
00531   Compare strings according to collation, without end space.
00532 
00533   SYNOPSIS
00534     sortcmp()
00535     s   First string
00536     t   Second string
00537     cs    Collation
00538 
00539   NOTE:
00540     Normally this is case sensitive comparison
00541 
00542   RETURN
00543   < 0 s < t
00544   0 s == t
00545   > 0 s > t
00546 */
00547 
00548 
00549 int sortcmp(const String *s,const String *t, const CHARSET_INFO * const cs)
00550 {
00551  return cs->coll->strnncollsp(cs,
00552                               (unsigned char *) s->ptr(),s->length(),
00553                               (unsigned char *) t->ptr(),t->length(), 0);
00554 }
00555 
00556 
00557 /*
00558   Compare strings byte by byte. End spaces are also compared.
00559 
00560   SYNOPSIS
00561     stringcmp()
00562     s   First string
00563     t   Second string
00564 
00565   NOTE:
00566     Strings are compared as a stream of unsigned chars
00567 
00568   RETURN
00569   < 0 s < t
00570   0 s == t
00571   > 0 s > t
00572 */
00573 
00574 
00575 int stringcmp(const String *s,const String *t)
00576 {
00577   size_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
00578   int cmp= memcmp(s->ptr(), t->ptr(), len);
00579   return (cmp) ? cmp : (int) (s_len - t_len);
00580 }
00581 
00582 
00583 String *copy_if_not_alloced(String *to,String *from,size_t from_length)
00584 {
00585   if (from->Alloced_length >= from_length)
00586     return from;
00587   if (from->alloced || !to || from == to)
00588   {
00589     (void) from->realloc(from_length);
00590     return from;
00591   }
00592   if (to->realloc(from_length))
00593     return from;        // Actually an error
00594   if ((to->str_length= min(from->str_length,from_length)))
00595     memcpy(to->Ptr,from->Ptr,to->str_length);
00596   to->str_charset=from->str_charset;
00597   return to;
00598 }
00599 
00600 
00601 /****************************************************************************
00602   Help functions
00603 ****************************************************************************/
00604 
00605 /*
00606   copy a string,
00607   with optional character set conversion,
00608   with optional left padding (for binary -> UCS2 conversion)
00609 
00610   SYNOPSIS
00611     well_formed_copy_nchars()
00612     to           Store result here
00613     to_length                Maxinum length of "to" string
00614     to_cs        Character set of "to" string
00615     from         Copy from here
00616     from_length        Length of from string
00617     from_cs        From character set
00618     nchars                   Copy not more that nchars characters
00619     well_formed_error_pos    Return position when "from" is not well formed
00620                              or NULL otherwise.
00621     cannot_convert_error_pos Return position where a not convertable
00622                              character met, or NULL otherwise.
00623     from_end_pos             Return position where scanning of "from"
00624                              string stopped.
00625   NOTES
00626 
00627   RETURN
00628     length of bytes copied to 'to'
00629 */
00630 
00631 
00632 size_t
00633 well_formed_copy_nchars(const CHARSET_INFO * const to_cs,
00634                         char *to, size_t to_length,
00635                         const CHARSET_INFO * const from_cs,
00636                         const char *from, size_t from_length,
00637                         size_t nchars,
00638                         const char **well_formed_error_pos,
00639                         const char **cannot_convert_error_pos,
00640                         const char **from_end_pos)
00641 {
00642   size_t res;
00643 
00644   assert((to_cs == &my_charset_bin) ||
00645          (from_cs == &my_charset_bin) ||
00646          (to_cs == from_cs) ||
00647          my_charset_same(from_cs, to_cs));
00648 
00649   if (to_length < to_cs->mbminlen || !nchars)
00650   {
00651     *from_end_pos= from;
00652     *cannot_convert_error_pos= NULL;
00653     *well_formed_error_pos= NULL;
00654     return 0;
00655   }
00656 
00657   if (to_cs == &my_charset_bin)
00658   {
00659     res= min(min(nchars, to_length), from_length);
00660     memmove(to, from, res);
00661     *from_end_pos= from + res;
00662     *well_formed_error_pos= NULL;
00663     *cannot_convert_error_pos= NULL;
00664   }
00665   else
00666   {
00667     int well_formed_error;
00668     size_t from_offset;
00669 
00670     if ((from_offset= (from_length % to_cs->mbminlen)) &&
00671         (from_cs == &my_charset_bin))
00672     {
00673       /*
00674         Copying from BINARY to UCS2 needs to prepend zeros sometimes:
00675         INSERT INTO t1 (ucs2_column) VALUES (0x01);
00676         0x01 -> 0x0001
00677       */
00678       size_t pad_length= to_cs->mbminlen - from_offset;
00679       memset(to, 0, pad_length);
00680       memmove(to + pad_length, from, from_offset);
00681       nchars--;
00682       from+= from_offset;
00683       from_length-= from_offset;
00684       to+= to_cs->mbminlen;
00685       to_length-= to_cs->mbminlen;
00686     }
00687 
00688     set_if_smaller(from_length, to_length);
00689     res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
00690                                       nchars, &well_formed_error);
00691     memmove(to, from, res);
00692     *from_end_pos= from + res;
00693     *well_formed_error_pos= well_formed_error ? from + res : NULL;
00694     *cannot_convert_error_pos= NULL;
00695     if (from_offset)
00696       res+= to_cs->mbminlen;
00697   }
00698 
00699   return res;
00700 }
00701 
00702 
00703 
00704 
00705 void String::print(String *str)
00706 {
00707   char *st= (char*)Ptr, *end= st+str_length;
00708   for (; st < end; st++)
00709   {
00710     unsigned char c= *st;
00711     switch (c)
00712     {
00713     case '\\':
00714       str->append("\\\\", sizeof("\\\\")-1);
00715       break;
00716     case '\0':
00717       str->append("\\0", sizeof("\\0")-1);
00718       break;
00719     case '\'':
00720       str->append("\\'", sizeof("\\'")-1);
00721       break;
00722     case '\n':
00723       str->append("\\n", sizeof("\\n")-1);
00724       break;
00725     case '\r':
00726       str->append("\\r", sizeof("\\r")-1);
00727       break;
00728     case '\032': // Ctrl-Z
00729       str->append("\\Z", sizeof("\\Z")-1);
00730       break;
00731     default:
00732       str->append(c);
00733     }
00734   }
00735 }
00736 
00737 /*
00738   Quote the given identifier.
00739   If the given identifier is empty, it will be quoted.
00740 
00741   SYNOPSIS
00742   append_identifier()
00743   name                  the identifier to be appended
00744   name_length           length of the appending identifier
00745 */
00746 
00747 /* Factor the extern out */
00748 extern const CHARSET_INFO *system_charset_info, *files_charset_info;
00749 
00750 void String::append_identifier(const char *name, size_t in_length)
00751 {
00752   const char *name_end;
00753   char quote_char;
00754   int q= '`';
00755 
00756   /*
00757     The identifier must be quoted as it includes a quote character or
00758    it's a keyword
00759   */
00760 
00761   reserve(in_length*2 + 2);
00762   quote_char= (char) q;
00763   append(&quote_char, 1, system_charset_info);
00764 
00765   for (name_end= name+in_length ; name < name_end ; name+= in_length)
00766   {
00767     unsigned char chr= (unsigned char) *name;
00768     in_length= my_mbcharlen(system_charset_info, chr);
00769     /*
00770       my_mbcharlen can return 0 on a wrong multibyte
00771       sequence. It is possible when upgrading from 4.0,
00772       and identifier contains some accented characters.
00773       The manual says it does not work. So we'll just
00774       change length to 1 not to hang in the endless loop.
00775     */
00776     if (!in_length)
00777       in_length= 1;
00778     if (in_length == 1 && chr == (unsigned char) quote_char)
00779       append(&quote_char, 1, system_charset_info);
00780     append(name, in_length, system_charset_info);
00781   }
00782   append(&quote_char, 1, system_charset_info);
00783 }
00784 
00785 
00786 /*
00787   Exchange state of this object and argument.
00788 
00789   SYNOPSIS
00790     String::swap()
00791 
00792   RETURN
00793     Target string will contain state of this object and vice versa.
00794 */
00795 
00796 void String::swap(String &s)
00797 {
00798   std::swap(Ptr, s.Ptr);
00799   std::swap(str_length, s.str_length);
00800   std::swap(Alloced_length, s.Alloced_length);
00801   std::swap(alloced, s.alloced);
00802   std::swap(str_charset, s.str_charset);
00803 }
00804 
00805 void String::q_append(const size_t n)
00806 {
00807   int8store(Ptr + str_length, n);
00808   str_length += 4;
00809 }
00810 void String::q_append(double d)
00811 {
00812   float8store(Ptr + str_length, d);
00813   str_length += 8;
00814 }
00815 void String::q_append(double *d)
00816 {
00817   float8store(Ptr + str_length, *d);
00818   str_length += 8;
00819 }
00820 void String::q_append(const char *data, size_t data_len)
00821 {
00822   memcpy(Ptr + str_length, data, data_len);
00823   str_length += data_len;
00824 }
00825 
00826 void String::write_at_position(int position, size_t value)
00827 {
00828   int8store(Ptr + position,value);
00829 }
00830 bool check_if_only_end_space(const CHARSET_INFO * const cs, char *str,
00831                              char *end)
00832 {
00833   return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
00834 }
00835 
00836 std::ostream& operator<<(std::ostream& output, const String &str)
00837 {
00838   output << "String:(";
00839   output <<  const_cast<String&>(str).c_str();
00840   output << ", ";
00841   output << str.length();
00842   output << ")";
00843 
00844   return output;  // for multiple << operators.
00845 }
00846 
00847 } /* namespace drizzled */
00848 
00849 bool operator==(const drizzled::String &s1, const drizzled::String &s2)
00850 {
00851   return stringcmp(&s1,&s2) == 0;
00852 }
00853 
00854 bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
00855 {
00856   return !(s1 == s2);
00857 }
00858