~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
/* This file is originally from the mysql distribution. Coded by monty */
17
17
 
18
 
#include "config.h"
19
 
 
20
 
#include "drizzled/internal/my_sys.h"
21
 
#include "drizzled/internal/m_string.h"
22
 
#include "drizzled/charset.h"
23
 
#include "drizzled/global_charset_info.h"
 
18
#include "global.h"
 
19
#include <mysys/my_sys.h>
 
20
#include <mystrings/m_string.h>
24
21
 
25
22
#include <algorithm>
26
23
 
27
 
#include "drizzled/sql_string.h"
28
 
 
29
 
using namespace std;
30
 
 
31
 
namespace drizzled
32
 
{
33
 
 
34
 
// Converstion functions to and from std::string.
35
 
 
36
 
std::string String_to_std_string(String const& s)
37
 
{
38
 
   return std::string(s.ptr(), s.length());
39
 
}
40
 
 
41
 
String* set_String_from_std_string(String* s, std::string const& cs)
42
 
{
43
 
   s->set_ascii(cs.c_str(), cs.length());
44
 
   s->copy();
45
 
   return s;
46
 
}
 
24
/*
 
25
  The following extern declarations are ok as these are interface functions
 
26
  required by the string function
 
27
*/
 
28
 
 
29
extern unsigned char* sql_alloc(unsigned size);
 
30
extern void sql_element_free(void *ptr);
 
31
 
 
32
#include "sql_string.h"
47
33
 
48
34
/*****************************************************************************
49
35
** String functions
50
36
*****************************************************************************/
51
37
 
52
 
String::String()
53
 
  : Ptr(NULL),
54
 
    str_length(0),
55
 
    Alloced_length(0),
56
 
    alloced(false),
57
 
    str_charset(&my_charset_bin)
58
 
{ }
59
 
 
60
 
 
61
 
String::String(uint32_t length_arg)
62
 
  : Ptr(NULL),
63
 
    str_length(0),
64
 
    Alloced_length(0),
65
 
    alloced(false),
66
 
    str_charset(&my_charset_bin)
67
 
{
68
 
  (void) real_alloc(length_arg);
69
 
}
70
 
 
71
 
String::String(const char *str, const CHARSET_INFO * const cs)
72
 
  : Ptr(const_cast<char *>(str)),
73
 
    str_length(static_cast<uint32_t>(strlen(str))),
74
 
    Alloced_length(0),
75
 
    alloced(false),
76
 
    str_charset(cs)
77
 
{ }
78
 
 
79
 
 
80
 
String::String(const char *str, uint32_t len, const CHARSET_INFO * const cs)
81
 
  : Ptr(const_cast<char *>(str)),
82
 
    str_length(len),
83
 
    Alloced_length(0),
84
 
    alloced(false),
85
 
    str_charset(cs)
86
 
{ }
87
 
 
88
 
 
89
 
String::String(char *str, uint32_t len, const CHARSET_INFO * const cs)
90
 
  : Ptr(str),
91
 
    str_length(len),
92
 
    Alloced_length(len),
93
 
    alloced(false),
94
 
    str_charset(cs)
95
 
{ }
96
 
 
97
 
 
98
 
String::String(const String &str)
99
 
  : Ptr(str.Ptr),
100
 
    str_length(str.str_length),
101
 
    Alloced_length(str.Alloced_length),
102
 
    alloced(false),
103
 
    str_charset(str.str_charset)
104
 
{ }
105
 
 
106
 
 
107
 
void *String::operator new(size_t size, memory::Root *mem_root)
108
 
{
109
 
  return alloc_root(mem_root, static_cast<uint32_t>(size));
110
 
}
111
 
 
112
 
String::~String() { free(); }
113
 
 
114
38
bool String::real_alloc(uint32_t arg_length)
115
39
{
116
40
  arg_length=ALIGN_SIZE(arg_length+1);
118
42
  if (Alloced_length < arg_length)
119
43
  {
120
44
    free();
121
 
    if (!(Ptr=(char*) malloc(arg_length)))
 
45
    if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
122
46
      return true;
123
47
    Alloced_length=arg_length;
124
48
    alloced=1;
141
65
    char *new_ptr;
142
66
    if (alloced)
143
67
    {
144
 
      if ((new_ptr= (char*) ::realloc(Ptr,len)))
 
68
      if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
145
69
      {
146
70
        Ptr=new_ptr;
147
71
        Alloced_length=len;
149
73
      else
150
74
        return true;                            // Signal error
151
75
    }
152
 
    else if ((new_ptr= (char*) malloc(len)))
 
76
    else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
153
77
    {
154
78
      if (str_length)                           // Avoid bugs in memcpy on AIX
155
79
        memcpy(new_ptr,Ptr,str_length);
186
110
  str_charset=cs;
187
111
  if (decimals >= NOT_FIXED_DEC)
188
112
  {
189
 
    len= internal::my_gcvt(num,
190
 
                           internal::MY_GCVT_ARG_DOUBLE,
191
 
                           sizeof(buff) - 1, buff, NULL);
 
113
    len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
192
114
    return copy(buff, len, &my_charset_utf8_general_ci, cs, &dummy_errors);
193
115
  }
194
 
  len= internal::my_fcvt(num, decimals, buff, NULL);
 
116
  len= my_fcvt(num, decimals, buff, NULL);
195
117
  return copy(buff, (uint32_t) len, &my_charset_utf8_general_ci, cs,
196
118
              &dummy_errors);
197
119
}
259
181
{
260
182
  *offset= 0;
261
183
  if (!to_cs ||
262
 
      (to_cs == &my_charset_bin) ||
 
184
      (to_cs == &my_charset_bin) || 
263
185
      (to_cs == from_cs) ||
264
186
      my_charset_same(from_cs, to_cs) ||
265
187
      ((from_cs == &my_charset_bin) &&
269
191
}
270
192
 
271
193
 
 
194
/*
 
195
  Copy a multi-byte character sets with adding leading zeros.
 
196
 
 
197
  SYNOPSIS
 
198
 
 
199
  copy_aligned()
 
200
  str                   String to copy
 
201
  arg_length            Length of string. This should NOT be dividable with
 
202
                        cs->mbminlen.
 
203
  offset                arg_length % cs->mb_minlength
 
204
  cs                    Character set for 'str'
 
205
 
 
206
  NOTES
 
207
    For real multi-byte, ascii incompatible charactser sets,
 
208
    like UCS-2, add leading zeros if we have an incomplete character.
 
209
    Thus, 
 
210
      SELECT _ucs2 0xAA 
 
211
    will automatically be converted into
 
212
      SELECT _ucs2 0x00AA
 
213
 
 
214
  RETURN
 
215
    0  ok
 
216
    1  error
 
217
*/
 
218
 
 
219
bool String::copy_aligned(const char *str,uint32_t arg_length, uint32_t offset,
 
220
                          const CHARSET_INFO * const cs)
 
221
{
 
222
  /* How many bytes are in incomplete character */
 
223
  offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
 
224
  assert(offset && offset != cs->mbmaxlen);
 
225
 
 
226
  uint32_t aligned_length= arg_length + offset;
 
227
  if (alloc(aligned_length))
 
228
    return true;
 
229
  
 
230
  /*
 
231
    Note, this is only safe for big-endian UCS-2.
 
232
    If we add little-endian UCS-2 sometimes, this code
 
233
    will be more complicated. But it's OK for now.
 
234
  */
 
235
  memset(Ptr, 0, offset);
 
236
  memcpy(Ptr + offset, str, arg_length);
 
237
  Ptr[aligned_length]=0;
 
238
  /* str_length is always >= 0 as arg_length is != 0 */
 
239
  str_length= aligned_length;
 
240
  str_charset= cs;
 
241
  return false;
 
242
}
272
243
 
273
244
 
274
245
bool String::set_or_copy_aligned(const char *str,uint32_t arg_length,
275
246
                                 const CHARSET_INFO * const cs)
276
247
{
277
248
  /* How many bytes are in incomplete character */
278
 
  uint32_t offset= (arg_length % cs->mbminlen);
279
 
 
280
 
  assert(!offset); /* All characters are complete, just copy */
281
 
 
282
 
  set(str, arg_length, cs);
283
 
  return false;
 
249
  uint32_t offset= (arg_length % cs->mbminlen); 
 
250
  
 
251
  if (!offset) /* All characters are complete, just copy */
 
252
  {
 
253
    set(str, arg_length, cs);
 
254
    return false;
 
255
  }
 
256
  return copy_aligned(str, arg_length, offset, cs);
284
257
}
285
258
 
286
259
        /* Copy with charset conversion */
287
260
 
288
261
bool String::copy(const char *str, uint32_t arg_length,
289
 
                          const CHARSET_INFO * const,
 
262
                          const CHARSET_INFO * const from_cs,
290
263
                                  const CHARSET_INFO * const to_cs, uint32_t *errors)
291
264
{
292
 
  *errors= 0;
293
 
  return copy(str, arg_length, to_cs);
 
265
  uint32_t offset;
 
266
  if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
 
267
  {
 
268
    *errors= 0;
 
269
    return copy(str, arg_length, to_cs);
 
270
  }
 
271
  if ((from_cs == &my_charset_bin) && offset)
 
272
  {
 
273
    *errors= 0;
 
274
    return copy_aligned(str, arg_length, offset, to_cs);
 
275
  }
 
276
  uint32_t new_length= to_cs->mbmaxlen*arg_length;
 
277
  if (alloc(new_length))
 
278
    return true;
 
279
  str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
 
280
                              str, arg_length, from_cs, errors);
 
281
  str_charset=to_cs;
 
282
  return false;
294
283
}
295
284
 
296
285
 
297
286
/*
298
287
  Set a string to the value of a latin1-string, keeping the original charset
299
 
 
 
288
  
300
289
  SYNOPSIS
301
290
    copy_or_set()
302
291
    str                 String of a simple charset (latin1)
324
313
  return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
325
314
}
326
315
 
 
316
 
 
317
/* This is used by mysql.cc */
 
318
 
 
319
bool String::fill(uint32_t max_length,char fill_char)
 
320
{
 
321
  if (str_length > max_length)
 
322
    Ptr[str_length=max_length]=0;
 
323
  else
 
324
  {
 
325
    if (realloc(max_length))
 
326
      return true;
 
327
    memset(Ptr+str_length, fill_char, max_length-str_length);
 
328
    str_length=max_length;
 
329
  }
 
330
  return false;
 
331
}
 
332
 
327
333
bool String::append(const String &s)
328
334
{
329
335
  if (s.length())
347
353
    return false;
348
354
 
349
355
  /*
 
356
    For an ASCII incompatible string, e.g. UCS-2, we need to convert
 
357
  */
 
358
  if (str_charset->mbminlen > 1)
 
359
  {
 
360
    uint32_t add_length=arg_length * str_charset->mbmaxlen;
 
361
    uint32_t dummy_errors;
 
362
    if (realloc(str_length+ add_length))
 
363
      return true;
 
364
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
365
                                  s, arg_length, &my_charset_utf8_general_ci,
 
366
                                  &dummy_errors);
 
367
    return false;
 
368
  }
 
369
 
 
370
  /*
350
371
    For an ASCII compatinble string we can just append.
351
372
  */
352
373
  if (realloc(str_length+arg_length))
372
393
  with character set recoding
373
394
*/
374
395
 
375
 
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const)
376
 
{
377
 
  if (realloc(str_length + arg_length))
378
 
    return true;
379
 
  memcpy(Ptr + str_length, s, arg_length);
380
 
  str_length+= arg_length;
381
 
 
382
 
  return false;
383
 
}
384
 
 
 
396
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const cs)
 
397
{
 
398
  uint32_t dummy_offset;
 
399
  
 
400
  if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
 
401
  {
 
402
    uint32_t add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
 
403
    uint32_t dummy_errors;
 
404
    if (realloc(str_length + add_length)) 
 
405
      return true;
 
406
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
407
                                  s, arg_length, cs, &dummy_errors);
 
408
  }
 
409
  else
 
410
  {
 
411
    if (realloc(str_length + arg_length)) 
 
412
      return true;
 
413
    memcpy(Ptr + str_length, s, arg_length);
 
414
    str_length+= arg_length;
 
415
  }
 
416
  return false;
 
417
}
 
418
 
 
419
 
 
420
bool String::append(IO_CACHE* file, uint32_t arg_length)
 
421
{
 
422
  if (realloc(str_length+arg_length))
 
423
    return true;
 
424
  if (my_b_read(file, (unsigned char*) Ptr + str_length, arg_length))
 
425
  {
 
426
    shrink(str_length);
 
427
    return true;
 
428
  }
 
429
  str_length+=arg_length;
 
430
  return false;
 
431
}
385
432
 
386
433
bool String::append_with_prefill(const char *s,uint32_t arg_length,
387
434
                 uint32_t full_length, char fill_char)
490
537
    {
491
538
      if (to_length)
492
539
        memcpy(Ptr+offset,to,to_length);
493
 
      memmove(Ptr+offset+to_length, Ptr+offset+arg_length,
494
 
              str_length-offset-arg_length);
 
540
      memcpy(Ptr+offset+to_length, Ptr+offset+arg_length,
 
541
             str_length-offset-arg_length);
495
542
    }
496
543
    else
497
544
    {
499
546
      {
500
547
        if (realloc(str_length+(uint32_t) diff))
501
548
          return true;
502
 
        internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
503
 
                            (unsigned char*) Ptr+str_length,
504
 
                            str_length-offset-arg_length);
 
549
        bmove_upp((unsigned char*) Ptr+str_length+diff, (unsigned char*) Ptr+str_length,
 
550
                  str_length-offset-arg_length);
505
551
      }
506
552
      if (to_length)
507
553
        memcpy(Ptr+offset,to,to_length);
512
558
}
513
559
 
514
560
 
 
561
// added by Holyfoot for "geometry" needs
 
562
int String::reserve(uint32_t space_needed, uint32_t grow_by)
 
563
{
 
564
  if (Alloced_length < str_length + space_needed)
 
565
  {
 
566
    if (realloc(Alloced_length + cmax(space_needed, grow_by) - 1))
 
567
      return true;
 
568
  }
 
569
  return false;
 
570
}
 
571
 
 
572
void String::qs_append(const char *str, uint32_t len)
 
573
{
 
574
  memcpy(Ptr + str_length, str, len + 1);
 
575
  str_length += len;
 
576
}
 
577
 
 
578
void String::qs_append(double d)
 
579
{
 
580
  char *buff = Ptr + str_length;
 
581
  str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff, NULL);
 
582
}
 
583
 
 
584
void String::qs_append(double *d)
 
585
{
 
586
  double ld;
 
587
  float8get(ld, (char*) d);
 
588
  qs_append(ld);
 
589
}
 
590
 
 
591
void String::qs_append(int i)
 
592
{
 
593
  char *buff= Ptr + str_length;
 
594
  char *end= int10_to_str(i, buff, -10);
 
595
  str_length+= (int) (end-buff);
 
596
}
 
597
 
 
598
void String::qs_append(uint32_t i)
 
599
{
 
600
  char *buff= Ptr + str_length;
 
601
  char *end= int10_to_str(i, buff, 10);
 
602
  str_length+= (int) (end-buff);
 
603
}
515
604
 
516
605
/*
517
606
  Compare strings according to collation, without end space.
560
649
 
561
650
int stringcmp(const String *s,const String *t)
562
651
{
563
 
  uint32_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
 
652
  uint32_t s_len=s->length(),t_len=t->length(),len=cmin(s_len,t_len);
564
653
  int cmp= memcmp(s->ptr(), t->ptr(), len);
565
654
  return (cmp) ? cmp : (int) (s_len - t_len);
566
655
}
577
666
  }
578
667
  if (to->realloc(from_length))
579
668
    return from;                                // Actually an error
580
 
  if ((to->str_length= min(from->str_length,from_length)))
 
669
  if ((to->str_length=cmin(from->str_length,from_length)))
581
670
    memcpy(to->Ptr,from->Ptr,to->str_length);
582
671
  to->str_charset=from->str_charset;
583
672
  return to;
589
678
****************************************************************************/
590
679
 
591
680
/*
 
681
  copy a string from one character set to another
 
682
  
 
683
  SYNOPSIS
 
684
    copy_and_convert()
 
685
    to                  Store result here
 
686
    to_cs               Character set of result string
 
687
    from                Copy from here
 
688
    from_length         Length of from string
 
689
    from_cs             From character set
 
690
 
 
691
  NOTES
 
692
    'to' must be big enough as form_length * to_cs->mbmaxlen
 
693
 
 
694
  RETURN
 
695
    length of bytes copied to 'to'
 
696
*/
 
697
 
 
698
 
 
699
static uint32_t
 
700
copy_and_convert_extended(char *to, uint32_t to_length,
 
701
                          const CHARSET_INFO * const to_cs, 
 
702
                          const char *from, uint32_t from_length,
 
703
                          const CHARSET_INFO * const from_cs,
 
704
                          uint32_t *errors)
 
705
{
 
706
  int         cnvres;
 
707
  my_wc_t     wc;
 
708
  const unsigned char *from_end= (const unsigned char*) from+from_length;
 
709
  char *to_start= to;
 
710
  unsigned char *to_end= (unsigned char*) to+to_length;
 
711
  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
712
  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
713
  uint32_t error_count= 0;
 
714
 
 
715
  while (1)
 
716
  {
 
717
    if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from,
 
718
                                      from_end)) > 0)
 
719
      from+= cnvres;
 
720
    else if (cnvres == MY_CS_ILSEQ)
 
721
    {
 
722
      error_count++;
 
723
      from++;
 
724
      wc= '?';
 
725
    }
 
726
    else if (cnvres > MY_CS_TOOSMALL)
 
727
    {
 
728
      /*
 
729
        A correct multibyte sequence detected
 
730
        But it doesn't have Unicode mapping.
 
731
      */
 
732
      error_count++;
 
733
      from+= (-cnvres);
 
734
      wc= '?';
 
735
    }
 
736
    else
 
737
      break;  // Not enough characters
 
738
 
 
739
outp:
 
740
    if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
741
      to+= cnvres;
 
742
    else if (cnvres == MY_CS_ILUNI && wc != '?')
 
743
    {
 
744
      error_count++;
 
745
      wc= '?';
 
746
      goto outp;
 
747
    }
 
748
    else
 
749
      break;
 
750
  }
 
751
  *errors= error_count;
 
752
  return (uint32_t) (to - to_start);
 
753
}
 
754
 
 
755
 
 
756
/*
 
757
  Optimized for quick copying of ASCII characters in the range 0x00..0x7F.
 
758
*/
 
759
uint32_t
 
760
copy_and_convert(char *to, uint32_t to_length, const CHARSET_INFO * const to_cs, 
 
761
                 const char *from, uint32_t from_length,
 
762
                                 const CHARSET_INFO * const from_cs, uint32_t *errors)
 
763
{
 
764
  /*
 
765
    If any of the character sets is not ASCII compatible,
 
766
    immediately switch to slow mb_wc->wc_mb method.
 
767
  */
 
768
  if ((to_cs->state | from_cs->state) & MY_CS_NONASCII)
 
769
    return copy_and_convert_extended(to, to_length, to_cs,
 
770
                                     from, from_length, from_cs, errors);
 
771
 
 
772
  uint32_t length= cmin(to_length, from_length), length2= length;
 
773
 
 
774
#if defined(__i386__)
 
775
  /*
 
776
    Special loop for i386, it allows to refer to a
 
777
    non-aligned memory block as UINT32, which makes
 
778
    it possible to copy four bytes at once. This
 
779
    gives about 10% performance improvement comparing
 
780
    to byte-by-byte loop.
 
781
  */
 
782
  for ( ; length >= 4; length-= 4, from+= 4, to+= 4)
 
783
  {
 
784
    if ((*(uint32_t*)from) & 0x80808080)
 
785
      break;
 
786
    *((uint32_t*) to)= *((const uint32_t*) from);
 
787
  }
 
788
#endif
 
789
 
 
790
  for (; ; *to++= *from++, length--)
 
791
  {
 
792
    if (!length)
 
793
    {
 
794
      *errors= 0;
 
795
      return length2;
 
796
    }
 
797
    if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */
 
798
    {
 
799
      uint32_t copied_length= length2 - length;
 
800
      to_length-= copied_length;
 
801
      from_length-= copied_length;
 
802
      return copied_length + copy_and_convert_extended(to, to_length,
 
803
                                                       to_cs,
 
804
                                                       from, from_length,
 
805
                                                       from_cs,
 
806
                                                       errors);
 
807
    }
 
808
  }
 
809
 
 
810
  assert(false); // Should never get to here
 
811
  return 0;           // Make compiler happy
 
812
}
 
813
 
 
814
 
 
815
/**
 
816
  Copy string with HEX-encoding of "bad" characters.
 
817
 
 
818
  @details This functions copies the string pointed by "src"
 
819
  to the string pointed by "dst". Not more than "srclen" bytes
 
820
  are read from "src". Any sequences of bytes representing
 
821
  a not-well-formed substring (according to cs) are hex-encoded,
 
822
  and all well-formed substrings (according to cs) are copied as is.
 
823
  Not more than "dstlen" bytes are written to "dst". The number 
 
824
  of bytes written to "dst" is returned.
 
825
  
 
826
   @param      cs       character set pointer of the destination string
 
827
   @param[out] dst      destination string
 
828
   @param      dstlen   size of dst
 
829
   @param      src      source string
 
830
   @param      srclen   length of src
 
831
 
 
832
   @retval     result length
 
833
*/
 
834
 
 
835
size_t
 
836
my_copy_with_hex_escaping(const CHARSET_INFO * const cs,
 
837
                          char *dst, size_t dstlen,
 
838
                          const char *src, size_t srclen)
 
839
{
 
840
  const char *srcend= src + srclen;
 
841
  char *dst0= dst;
 
842
 
 
843
  for ( ; src < srcend ; )
 
844
  {
 
845
    size_t chlen;
 
846
    if ((chlen= my_ismbchar(cs, src, srcend)))
 
847
    {
 
848
      if (dstlen < chlen)
 
849
        break; /* purecov: inspected */
 
850
      memcpy(dst, src, chlen);
 
851
      src+= chlen;
 
852
      dst+= chlen;
 
853
      dstlen-= chlen;
 
854
    }
 
855
    else if (*src & 0x80)
 
856
    {
 
857
      if (dstlen < 4)
 
858
        break; /* purecov: inspected */
 
859
      *dst++= '\\';
 
860
      *dst++= 'x';
 
861
      *dst++= _dig_vec_upper[((unsigned char) *src) >> 4];
 
862
      *dst++= _dig_vec_upper[((unsigned char) *src) & 15];
 
863
      src++;
 
864
      dstlen-= 4;
 
865
    }
 
866
    else
 
867
    {
 
868
      if (dstlen < 1)
 
869
        break; /* purecov: inspected */
 
870
      *dst++= *src++;
 
871
      dstlen--;
 
872
    }
 
873
  }
 
874
  return dst - dst0;
 
875
}
 
876
 
 
877
/*
592
878
  copy a string,
593
879
  with optional character set conversion,
594
880
  with optional left padding (for binary -> UCS2 conversion)
595
 
 
 
881
  
596
882
  SYNOPSIS
597
883
    well_formed_copy_nchars()
598
884
    to                       Store result here
627
913
{
628
914
  uint32_t res;
629
915
 
630
 
  assert((to_cs == &my_charset_bin) ||
631
 
         (from_cs == &my_charset_bin) ||
632
 
         (to_cs == from_cs) ||
633
 
         my_charset_same(from_cs, to_cs));
634
 
 
635
 
  if (to_length < to_cs->mbminlen || !nchars)
636
 
  {
 
916
  if ((to_cs == &my_charset_bin) || 
 
917
      (from_cs == &my_charset_bin) ||
 
918
      (to_cs == from_cs) ||
 
919
      my_charset_same(from_cs, to_cs))
 
920
  {
 
921
    if (to_length < to_cs->mbminlen || !nchars)
 
922
    {
 
923
      *from_end_pos= from;
 
924
      *cannot_convert_error_pos= NULL;
 
925
      *well_formed_error_pos= NULL;
 
926
      return 0;
 
927
    }
 
928
 
 
929
    if (to_cs == &my_charset_bin)
 
930
    {
 
931
      res= cmin(cmin(nchars, to_length), from_length);
 
932
      memmove(to, from, res);
 
933
      *from_end_pos= from + res;
 
934
      *well_formed_error_pos= NULL;
 
935
      *cannot_convert_error_pos= NULL;
 
936
    }
 
937
    else
 
938
    {
 
939
      int well_formed_error;
 
940
      uint32_t from_offset;
 
941
 
 
942
      if ((from_offset= (from_length % to_cs->mbminlen)) &&
 
943
          (from_cs == &my_charset_bin))
 
944
      {
 
945
        /*
 
946
          Copying from BINARY to UCS2 needs to prepend zeros sometimes:
 
947
          INSERT INTO t1 (ucs2_column) VALUES (0x01);
 
948
          0x01 -> 0x0001
 
949
        */
 
950
        uint32_t pad_length= to_cs->mbminlen - from_offset;
 
951
        memset(to, 0, pad_length);
 
952
        memmove(to + pad_length, from, from_offset);
 
953
        nchars--;
 
954
        from+= from_offset;
 
955
        from_length-= from_offset;
 
956
        to+= to_cs->mbminlen;
 
957
        to_length-= to_cs->mbminlen;
 
958
      }
 
959
 
 
960
      set_if_smaller(from_length, to_length);
 
961
      res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
 
962
                                        nchars, &well_formed_error);
 
963
      memmove(to, from, res);
 
964
      *from_end_pos= from + res;
 
965
      *well_formed_error_pos= well_formed_error ? from + res : NULL;
 
966
      *cannot_convert_error_pos= NULL;
 
967
      if (from_offset)
 
968
        res+= to_cs->mbminlen;
 
969
    }
 
970
  }
 
971
  else
 
972
  {
 
973
    int cnvres;
 
974
    my_wc_t wc;
 
975
    my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
976
    my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
977
    const unsigned char *from_end= (const unsigned char*) from + from_length;
 
978
    unsigned char *to_end= (unsigned char*) to + to_length;
 
979
    char *to_start= to;
 
980
    *well_formed_error_pos= NULL;
 
981
    *cannot_convert_error_pos= NULL;
 
982
 
 
983
    for ( ; nchars; nchars--)
 
984
    {
 
985
      const char *from_prev= from;
 
986
      if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from, from_end)) > 0)
 
987
        from+= cnvres;
 
988
      else if (cnvres == MY_CS_ILSEQ)
 
989
      {
 
990
        if (!*well_formed_error_pos)
 
991
          *well_formed_error_pos= from;
 
992
        from++;
 
993
        wc= '?';
 
994
      }
 
995
      else if (cnvres > MY_CS_TOOSMALL)
 
996
      {
 
997
        /*
 
998
          A correct multibyte sequence detected
 
999
          But it doesn't have Unicode mapping.
 
1000
        */
 
1001
        if (!*cannot_convert_error_pos)
 
1002
          *cannot_convert_error_pos= from;
 
1003
        from+= (-cnvres);
 
1004
        wc= '?';
 
1005
      }
 
1006
      else
 
1007
        break;  // Not enough characters
 
1008
 
 
1009
outp:
 
1010
      if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
1011
        to+= cnvres;
 
1012
      else if (cnvres == MY_CS_ILUNI && wc != '?')
 
1013
      {
 
1014
        if (!*cannot_convert_error_pos)
 
1015
          *cannot_convert_error_pos= from_prev;
 
1016
        wc= '?';
 
1017
        goto outp;
 
1018
      }
 
1019
      else
 
1020
      {
 
1021
        from= from_prev;
 
1022
        break;
 
1023
      }
 
1024
    }
637
1025
    *from_end_pos= from;
638
 
    *cannot_convert_error_pos= NULL;
639
 
    *well_formed_error_pos= NULL;
640
 
    return 0;
641
 
  }
642
 
 
643
 
  if (to_cs == &my_charset_bin)
644
 
  {
645
 
    res= min(min(nchars, to_length), from_length);
646
 
    memmove(to, from, res);
647
 
    *from_end_pos= from + res;
648
 
    *well_formed_error_pos= NULL;
649
 
    *cannot_convert_error_pos= NULL;
650
 
  }
651
 
  else
652
 
  {
653
 
    int well_formed_error;
654
 
    uint32_t from_offset;
655
 
 
656
 
    if ((from_offset= (from_length % to_cs->mbminlen)) &&
657
 
        (from_cs == &my_charset_bin))
658
 
    {
659
 
      /*
660
 
        Copying from BINARY to UCS2 needs to prepend zeros sometimes:
661
 
        INSERT INTO t1 (ucs2_column) VALUES (0x01);
662
 
        0x01 -> 0x0001
663
 
      */
664
 
      uint32_t pad_length= to_cs->mbminlen - from_offset;
665
 
      memset(to, 0, pad_length);
666
 
      memmove(to + pad_length, from, from_offset);
667
 
      nchars--;
668
 
      from+= from_offset;
669
 
      from_length-= from_offset;
670
 
      to+= to_cs->mbminlen;
671
 
      to_length-= to_cs->mbminlen;
672
 
    }
673
 
 
674
 
    set_if_smaller(from_length, to_length);
675
 
    res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
676
 
                                      nchars, &well_formed_error);
677
 
    memmove(to, from, res);
678
 
    *from_end_pos= from + res;
679
 
    *well_formed_error_pos= well_formed_error ? from + res : NULL;
680
 
    *cannot_convert_error_pos= NULL;
681
 
    if (from_offset)
682
 
      res+= to_cs->mbminlen;
683
 
  }
684
 
 
685
 
  return res;
 
1026
    res= to - to_start;
 
1027
  }
 
1028
  return (uint32_t) res;
686
1029
}
687
1030
 
688
1031
 
697
1040
    switch (c)
698
1041
    {
699
1042
    case '\\':
700
 
      str->append("\\\\", sizeof("\\\\")-1);
 
1043
      str->append(STRING_WITH_LEN("\\\\"));
701
1044
      break;
702
1045
    case '\0':
703
 
      str->append("\\0", sizeof("\\0")-1);
 
1046
      str->append(STRING_WITH_LEN("\\0"));
704
1047
      break;
705
1048
    case '\'':
706
 
      str->append("\\'", sizeof("\\'")-1);
 
1049
      str->append(STRING_WITH_LEN("\\'"));
707
1050
      break;
708
1051
    case '\n':
709
 
      str->append("\\n", sizeof("\\n")-1);
 
1052
      str->append(STRING_WITH_LEN("\\n"));
710
1053
      break;
711
1054
    case '\r':
712
 
      str->append("\\r", sizeof("\\r")-1);
 
1055
      str->append(STRING_WITH_LEN("\\r"));
713
1056
      break;
714
1057
    case '\032': // Ctrl-Z
715
 
      str->append("\\Z", sizeof("\\Z")-1);
 
1058
      str->append(STRING_WITH_LEN("\\Z"));
716
1059
      break;
717
1060
    default:
718
1061
      str->append(c);
720
1063
  }
721
1064
}
722
1065
 
723
 
/*
724
 
  Quote the given identifier.
725
 
  If the given identifier is empty, it will be quoted.
726
 
 
727
 
  SYNOPSIS
728
 
  append_identifier()
729
 
  name                  the identifier to be appended
730
 
  name_length           length of the appending identifier
731
 
*/
732
 
 
733
 
/* Factor the extern out */
734
 
extern const CHARSET_INFO *system_charset_info, *files_charset_info;
735
 
 
736
 
void String::append_identifier(const char *name, uint32_t in_length)
737
 
{
738
 
  const char *name_end;
739
 
  char quote_char;
740
 
  int q= '`';
741
 
 
742
 
  /*
743
 
    The identifier must be quoted as it includes a quote character or
744
 
   it's a keyword
745
 
  */
746
 
 
747
 
  reserve(in_length*2 + 2);
748
 
  quote_char= (char) q;
749
 
  append(&quote_char, 1, system_charset_info);
750
 
 
751
 
  for (name_end= name+in_length ; name < name_end ; name+= in_length)
752
 
  {
753
 
    unsigned char chr= (unsigned char) *name;
754
 
    in_length= my_mbcharlen(system_charset_info, chr);
755
 
    /*
756
 
      my_mbcharlen can return 0 on a wrong multibyte
757
 
      sequence. It is possible when upgrading from 4.0,
758
 
      and identifier contains some accented characters.
759
 
      The manual says it does not work. So we'll just
760
 
      change length to 1 not to hang in the endless loop.
761
 
    */
762
 
    if (!in_length)
763
 
      in_length= 1;
764
 
    if (in_length == 1 && chr == (unsigned char) quote_char)
765
 
      append(&quote_char, 1, system_charset_info);
766
 
    append(name, in_length, system_charset_info);
767
 
  }
768
 
  append(&quote_char, 1, system_charset_info);
769
 
}
770
 
 
771
1066
 
772
1067
/*
773
1068
  Exchange state of this object and argument.
787
1082
  std::swap(alloced, s.alloced);
788
1083
  std::swap(str_charset, s.str_charset);
789
1084
}
790
 
 
791
 
void String::q_append(const uint32_t n)
792
 
{
793
 
  int4store(Ptr + str_length, n);
794
 
  str_length += 4;
795
 
}
796
 
void String::q_append(double d)
797
 
{
798
 
  float8store(Ptr + str_length, d);
799
 
  str_length += 8;
800
 
}
801
 
void String::q_append(double *d)
802
 
{
803
 
  float8store(Ptr + str_length, *d);
804
 
  str_length += 8;
805
 
}
806
 
void String::q_append(const char *data, uint32_t data_len)
807
 
{
808
 
  memcpy(Ptr + str_length, data, data_len);
809
 
  str_length += data_len;
810
 
}
811
 
 
812
 
void String::write_at_position(int position, uint32_t value)
813
 
{
814
 
  int4store(Ptr + position,value);
815
 
}
816
 
bool check_if_only_end_space(const CHARSET_INFO * const cs, char *str,
817
 
                             char *end)
818
 
{
819
 
  return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
820
 
}
821
 
 
822
 
} /* namespace drizzled */
823
 
 
824
 
bool operator==(const drizzled::String &s1, const drizzled::String &s2)
825
 
{
826
 
  return stringcmp(&s1,&s2) == 0;
827
 
}
828
 
 
829
 
bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
830
 
{
831
 
  return !(s1 == s2);
832
 
}
833