~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

Merge of Jay

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include <mysys/my_sys.h>
20
20
#include <mystrings/m_string.h>
21
21
 
 
22
#include <algorithm>
 
23
 
 
24
using namespace std;
 
25
 
22
26
/*
23
27
  The following extern declarations are ok as these are interface functions
24
28
  required by the string function
25
29
*/
26
30
 
27
 
extern uchar* sql_alloc(unsigned size);
 
31
extern unsigned char* sql_alloc(unsigned size);
28
32
extern void sql_element_free(void *ptr);
29
33
 
30
34
#include "sql_string.h"
33
37
** String functions
34
38
*****************************************************************************/
35
39
 
 
40
String::~String() { free(); }
 
41
 
36
42
bool String::real_alloc(uint32_t arg_length)
37
43
{
38
44
  arg_length=ALIGN_SIZE(arg_length+1);
40
46
  if (Alloced_length < arg_length)
41
47
  {
42
48
    free();
43
 
    if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
 
49
    if (!(Ptr=(char*) malloc(arg_length)))
44
50
      return true;
45
51
    Alloced_length=arg_length;
46
52
    alloced=1;
63
69
    char *new_ptr;
64
70
    if (alloced)
65
71
    {
66
 
      if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
 
72
      if ((new_ptr= (char*) ::realloc(Ptr,len)))
67
73
      {
68
74
        Ptr=new_ptr;
69
75
        Alloced_length=len;
71
77
      else
72
78
        return true;                            // Signal error
73
79
    }
74
 
    else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
 
80
    else if ((new_ptr= (char*) malloc(len)))
75
81
    {
76
82
      if (str_length)                           // Avoid bugs in memcpy on AIX
77
83
        memcpy(new_ptr,Ptr,str_length);
89
95
 
90
96
bool String::set_int(int64_t num, bool unsigned_flag, const CHARSET_INFO * const cs)
91
97
{
92
 
  uint l=20*cs->mbmaxlen+1;
 
98
  uint32_t l=20*cs->mbmaxlen+1;
93
99
  int base= unsigned_flag ? 10 : -10;
94
100
 
95
101
  if (alloc(l))
99
105
  return false;
100
106
}
101
107
 
102
 
bool String::set_real(double num,uint decimals, const CHARSET_INFO * const cs)
 
108
bool String::set_real(double num,uint32_t decimals, const CHARSET_INFO * const cs)
103
109
{
104
110
  char buff[FLOATING_POINT_BUFFER];
105
 
  uint dummy_errors;
 
111
  uint32_t dummy_errors;
106
112
  size_t len;
107
113
 
108
114
  str_charset=cs;
109
115
  if (decimals >= NOT_FIXED_DEC)
110
116
  {
111
117
    len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
112
 
    return copy(buff, len, &my_charset_latin1, cs, &dummy_errors);
 
118
    return copy(buff, len, &my_charset_utf8_general_ci, cs, &dummy_errors);
113
119
  }
114
120
  len= my_fcvt(num, decimals, buff, NULL);
115
 
  return copy(buff, (uint32_t) len, &my_charset_latin1, cs,
 
121
  return copy(buff, (uint32_t) len, &my_charset_utf8_general_ci, cs,
116
122
              &dummy_errors);
117
123
}
118
124
 
179
185
{
180
186
  *offset= 0;
181
187
  if (!to_cs ||
182
 
      (to_cs == &my_charset_bin) || 
 
188
      (to_cs == &my_charset_bin) ||
183
189
      (to_cs == from_cs) ||
184
190
      my_charset_same(from_cs, to_cs) ||
185
191
      ((from_cs == &my_charset_bin) &&
189
195
}
190
196
 
191
197
 
192
 
/*
193
 
  Copy a multi-byte character sets with adding leading zeros.
194
 
 
195
 
  SYNOPSIS
196
 
 
197
 
  copy_aligned()
198
 
  str                   String to copy
199
 
  arg_length            Length of string. This should NOT be dividable with
200
 
                        cs->mbminlen.
201
 
  offset                arg_length % cs->mb_minlength
202
 
  cs                    Character set for 'str'
203
 
 
204
 
  NOTES
205
 
    For real multi-byte, ascii incompatible charactser sets,
206
 
    like UCS-2, add leading zeros if we have an incomplete character.
207
 
    Thus, 
208
 
      SELECT _ucs2 0xAA 
209
 
    will automatically be converted into
210
 
      SELECT _ucs2 0x00AA
211
 
 
212
 
  RETURN
213
 
    0  ok
214
 
    1  error
215
 
*/
216
 
 
217
 
bool String::copy_aligned(const char *str,uint32_t arg_length, uint32_t offset,
218
 
                          const CHARSET_INFO * const cs)
219
 
{
220
 
  /* How many bytes are in incomplete character */
221
 
  offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
222
 
  assert(offset && offset != cs->mbmaxlen);
223
 
 
224
 
  uint32_t aligned_length= arg_length + offset;
225
 
  if (alloc(aligned_length))
226
 
    return true;
227
 
  
228
 
  /*
229
 
    Note, this is only safe for big-endian UCS-2.
230
 
    If we add little-endian UCS-2 sometimes, this code
231
 
    will be more complicated. But it's OK for now.
232
 
  */
233
 
  memset(Ptr, 0, offset);
234
 
  memcpy(Ptr + offset, str, arg_length);
235
 
  Ptr[aligned_length]=0;
236
 
  /* str_length is always >= 0 as arg_length is != 0 */
237
 
  str_length= aligned_length;
238
 
  str_charset= cs;
239
 
  return false;
240
 
}
241
198
 
242
199
 
243
200
bool String::set_or_copy_aligned(const char *str,uint32_t arg_length,
244
201
                                 const CHARSET_INFO * const cs)
245
202
{
246
203
  /* How many bytes are in incomplete character */
247
 
  uint32_t offset= (arg_length % cs->mbminlen); 
248
 
  
249
 
  if (!offset) /* All characters are complete, just copy */
250
 
  {
251
 
    set(str, arg_length, cs);
252
 
    return false;
253
 
  }
254
 
  return copy_aligned(str, arg_length, offset, cs);
 
204
  uint32_t offset= (arg_length % cs->mbminlen);
 
205
 
 
206
  assert(!offset); /* All characters are complete, just copy */
 
207
 
 
208
  set(str, arg_length, cs);
 
209
  return false;
255
210
}
256
211
 
257
212
        /* Copy with charset conversion */
258
213
 
259
214
bool String::copy(const char *str, uint32_t arg_length,
260
 
                          const CHARSET_INFO * const from_cs,
261
 
                                  const CHARSET_INFO * const to_cs, uint *errors)
 
215
                          const CHARSET_INFO * const,
 
216
                                  const CHARSET_INFO * const to_cs, uint32_t *errors)
262
217
{
263
 
  uint32_t offset;
264
 
  if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
265
 
  {
266
 
    *errors= 0;
267
 
    return copy(str, arg_length, to_cs);
268
 
  }
269
 
  if ((from_cs == &my_charset_bin) && offset)
270
 
  {
271
 
    *errors= 0;
272
 
    return copy_aligned(str, arg_length, offset, to_cs);
273
 
  }
274
 
  uint32_t new_length= to_cs->mbmaxlen*arg_length;
275
 
  if (alloc(new_length))
276
 
    return true;
277
 
  str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
278
 
                              str, arg_length, from_cs, errors);
279
 
  str_charset=to_cs;
280
 
  return false;
 
218
  *errors= 0;
 
219
  return copy(str, arg_length, to_cs);
281
220
}
282
221
 
283
222
 
284
223
/*
285
224
  Set a string to the value of a latin1-string, keeping the original charset
286
 
  
 
225
 
287
226
  SYNOPSIS
288
227
    copy_or_set()
289
228
    str                 String of a simple charset (latin1)
307
246
    set(str, arg_length, str_charset);
308
247
    return 0;
309
248
  }
310
 
  uint dummy_errors;
311
 
  return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors);
312
 
}
313
 
 
314
 
 
315
 
/* This is used by mysql.cc */
316
 
 
317
 
bool String::fill(uint32_t max_length,char fill_char)
318
 
{
319
 
  if (str_length > max_length)
320
 
    Ptr[str_length=max_length]=0;
321
 
  else
322
 
  {
323
 
    if (realloc(max_length))
324
 
      return true;
325
 
    memset(Ptr+str_length, fill_char, max_length-str_length);
326
 
    str_length=max_length;
327
 
  }
328
 
  return false;
 
249
  uint32_t dummy_errors;
 
250
  return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
329
251
}
330
252
 
331
253
bool String::append(const String &s)
351
273
    return false;
352
274
 
353
275
  /*
354
 
    For an ASCII incompatible string, e.g. UCS-2, we need to convert
355
 
  */
356
 
  if (str_charset->mbminlen > 1)
357
 
  {
358
 
    uint32_t add_length=arg_length * str_charset->mbmaxlen;
359
 
    uint dummy_errors;
360
 
    if (realloc(str_length+ add_length))
361
 
      return true;
362
 
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
363
 
                                  s, arg_length, &my_charset_latin1,
364
 
                                  &dummy_errors);
365
 
    return false;
366
 
  }
367
 
 
368
 
  /*
369
276
    For an ASCII compatinble string we can just append.
370
277
  */
371
278
  if (realloc(str_length+arg_length))
391
298
  with character set recoding
392
299
*/
393
300
 
394
 
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const cs)
395
 
{
396
 
  uint32_t dummy_offset;
397
 
  
398
 
  if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
399
 
  {
400
 
    uint32_t add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
401
 
    uint dummy_errors;
402
 
    if (realloc(str_length + add_length)) 
403
 
      return true;
404
 
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
405
 
                                  s, arg_length, cs, &dummy_errors);
406
 
  }
407
 
  else
408
 
  {
409
 
    if (realloc(str_length + arg_length)) 
410
 
      return true;
411
 
    memcpy(Ptr + str_length, s, arg_length);
412
 
    str_length+= arg_length;
413
 
  }
414
 
  return false;
415
 
}
416
 
 
417
 
 
418
 
bool String::append(IO_CACHE* file, uint32_t arg_length)
419
 
{
420
 
  if (realloc(str_length+arg_length))
421
 
    return true;
422
 
  if (my_b_read(file, (uchar*) Ptr + str_length, arg_length))
423
 
  {
424
 
    shrink(str_length);
425
 
    return true;
426
 
  }
427
 
  str_length+=arg_length;
428
 
  return false;
429
 
}
 
301
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const)
 
302
{
 
303
  if (realloc(str_length + arg_length))
 
304
    return true;
 
305
  memcpy(Ptr + str_length, s, arg_length);
 
306
  str_length+= arg_length;
 
307
 
 
308
  return false;
 
309
}
 
310
 
430
311
 
431
312
bool String::append_with_prefill(const char *s,uint32_t arg_length,
432
313
                 uint32_t full_length, char fill_char)
535
416
    {
536
417
      if (to_length)
537
418
        memcpy(Ptr+offset,to,to_length);
538
 
      memcpy(Ptr+offset+to_length, Ptr+offset+arg_length,
539
 
             str_length-offset-arg_length);
 
419
      memmove(Ptr+offset+to_length, Ptr+offset+arg_length,
 
420
              str_length-offset-arg_length);
540
421
    }
541
422
    else
542
423
    {
544
425
      {
545
426
        if (realloc(str_length+(uint32_t) diff))
546
427
          return true;
547
 
        bmove_upp((uchar*) Ptr+str_length+diff, (uchar*) Ptr+str_length,
 
428
        bmove_upp((unsigned char*) Ptr+str_length+diff, (unsigned char*) Ptr+str_length,
548
429
                  str_length-offset-arg_length);
549
430
      }
550
431
      if (to_length)
556
437
}
557
438
 
558
439
 
559
 
// added by Holyfoot for "geometry" needs
560
 
int String::reserve(uint32_t space_needed, uint32_t grow_by)
561
 
{
562
 
  if (Alloced_length < str_length + space_needed)
563
 
  {
564
 
    if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
565
 
      return true;
566
 
  }
567
 
  return false;
568
 
}
569
 
 
570
 
void String::qs_append(const char *str, uint32_t len)
571
 
{
572
 
  memcpy(Ptr + str_length, str, len + 1);
573
 
  str_length += len;
574
 
}
575
 
 
576
 
void String::qs_append(double d)
577
 
{
578
 
  char *buff = Ptr + str_length;
579
 
  str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff, NULL);
580
 
}
581
 
 
582
 
void String::qs_append(double *d)
583
 
{
584
 
  double ld;
585
 
  float8get(ld, (char*) d);
586
 
  qs_append(ld);
587
 
}
588
 
 
589
 
void String::qs_append(int i)
590
 
{
591
 
  char *buff= Ptr + str_length;
592
 
  char *end= int10_to_str(i, buff, -10);
593
 
  str_length+= (int) (end-buff);
594
 
}
595
 
 
596
 
void String::qs_append(uint i)
597
 
{
598
 
  char *buff= Ptr + str_length;
599
 
  char *end= int10_to_str(i, buff, 10);
600
 
  str_length+= (int) (end-buff);
601
 
}
602
440
 
603
441
/*
604
442
  Compare strings according to collation, without end space.
622
460
int sortcmp(const String *s,const String *t, const CHARSET_INFO * const cs)
623
461
{
624
462
 return cs->coll->strnncollsp(cs,
625
 
                              (uchar *) s->ptr(),s->length(),
626
 
                              (uchar *) t->ptr(),t->length(), 0);
 
463
                              (unsigned char *) s->ptr(),s->length(),
 
464
                              (unsigned char *) t->ptr(),t->length(), 0);
627
465
}
628
466
 
629
467
 
636
474
    t           Second string
637
475
 
638
476
  NOTE:
639
 
    Strings are compared as a stream of uchars
 
477
    Strings are compared as a stream of unsigned chars
640
478
 
641
479
  RETURN
642
480
  < 0   s < t
647
485
 
648
486
int stringcmp(const String *s,const String *t)
649
487
{
650
 
  uint32_t s_len=s->length(),t_len=t->length(),len=min(s_len,t_len);
 
488
  uint32_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
651
489
  int cmp= memcmp(s->ptr(), t->ptr(), len);
652
490
  return (cmp) ? cmp : (int) (s_len - t_len);
653
491
}
664
502
  }
665
503
  if (to->realloc(from_length))
666
504
    return from;                                // Actually an error
667
 
  if ((to->str_length=min(from->str_length,from_length)))
 
505
  if ((to->str_length= min(from->str_length,from_length)))
668
506
    memcpy(to->Ptr,from->Ptr,to->str_length);
669
507
  to->str_charset=from->str_charset;
670
508
  return to;
675
513
  Help functions
676
514
****************************************************************************/
677
515
 
678
 
/*
679
 
  copy a string from one character set to another
680
 
  
681
 
  SYNOPSIS
682
 
    copy_and_convert()
683
 
    to                  Store result here
684
 
    to_cs               Character set of result string
685
 
    from                Copy from here
686
 
    from_length         Length of from string
687
 
    from_cs             From character set
688
 
 
689
 
  NOTES
690
 
    'to' must be big enough as form_length * to_cs->mbmaxlen
691
 
 
692
 
  RETURN
693
 
    length of bytes copied to 'to'
694
 
*/
695
 
 
696
 
 
697
 
static uint32_t
698
 
copy_and_convert_extended(char *to, uint32_t to_length,
699
 
                          const CHARSET_INFO * const to_cs, 
700
 
                          const char *from, uint32_t from_length,
701
 
                          const CHARSET_INFO * const from_cs,
702
 
                          uint *errors)
703
 
{
704
 
  int         cnvres;
705
 
  my_wc_t     wc;
706
 
  const uchar *from_end= (const uchar*) from+from_length;
707
 
  char *to_start= to;
708
 
  uchar *to_end= (uchar*) to+to_length;
709
 
  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
710
 
  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
711
 
  uint error_count= 0;
712
 
 
713
 
  while (1)
714
 
  {
715
 
    if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from,
716
 
                                      from_end)) > 0)
717
 
      from+= cnvres;
718
 
    else if (cnvres == MY_CS_ILSEQ)
719
 
    {
720
 
      error_count++;
721
 
      from++;
722
 
      wc= '?';
723
 
    }
724
 
    else if (cnvres > MY_CS_TOOSMALL)
725
 
    {
726
 
      /*
727
 
        A correct multibyte sequence detected
728
 
        But it doesn't have Unicode mapping.
729
 
      */
730
 
      error_count++;
731
 
      from+= (-cnvres);
732
 
      wc= '?';
733
 
    }
734
 
    else
735
 
      break;  // Not enough characters
736
 
 
737
 
outp:
738
 
    if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
739
 
      to+= cnvres;
740
 
    else if (cnvres == MY_CS_ILUNI && wc != '?')
741
 
    {
742
 
      error_count++;
743
 
      wc= '?';
744
 
      goto outp;
745
 
    }
746
 
    else
747
 
      break;
748
 
  }
749
 
  *errors= error_count;
750
 
  return (uint32_t) (to - to_start);
751
 
}
752
 
 
753
 
 
754
 
/*
755
 
  Optimized for quick copying of ASCII characters in the range 0x00..0x7F.
756
 
*/
757
 
uint32_t
758
 
copy_and_convert(char *to, uint32_t to_length, const CHARSET_INFO * const to_cs, 
759
 
                 const char *from, uint32_t from_length,
760
 
                                 const CHARSET_INFO * const from_cs, uint *errors)
761
 
{
762
 
  /*
763
 
    If any of the character sets is not ASCII compatible,
764
 
    immediately switch to slow mb_wc->wc_mb method.
765
 
  */
766
 
  if ((to_cs->state | from_cs->state) & MY_CS_NONASCII)
767
 
    return copy_and_convert_extended(to, to_length, to_cs,
768
 
                                     from, from_length, from_cs, errors);
769
 
 
770
 
  uint32_t length= min(to_length, from_length), length2= length;
771
 
 
772
 
#if defined(__i386__)
773
 
  /*
774
 
    Special loop for i386, it allows to refer to a
775
 
    non-aligned memory block as UINT32, which makes
776
 
    it possible to copy four bytes at once. This
777
 
    gives about 10% performance improvement comparing
778
 
    to byte-by-byte loop.
779
 
  */
780
 
  for ( ; length >= 4; length-= 4, from+= 4, to+= 4)
781
 
  {
782
 
    if ((*(uint32_t*)from) & 0x80808080)
783
 
      break;
784
 
    *((uint32_t*) to)= *((const uint32_t*) from);
785
 
  }
786
 
#endif
787
 
 
788
 
  for (; ; *to++= *from++, length--)
789
 
  {
790
 
    if (!length)
791
 
    {
792
 
      *errors= 0;
793
 
      return length2;
794
 
    }
795
 
    if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */
796
 
    {
797
 
      uint32_t copied_length= length2 - length;
798
 
      to_length-= copied_length;
799
 
      from_length-= copied_length;
800
 
      return copied_length + copy_and_convert_extended(to, to_length,
801
 
                                                       to_cs,
802
 
                                                       from, from_length,
803
 
                                                       from_cs,
804
 
                                                       errors);
805
 
    }
806
 
  }
807
 
 
808
 
  assert(false); // Should never get to here
809
 
  return 0;           // Make compiler happy
810
 
}
811
516
 
812
517
 
813
518
/**
818
523
  are read from "src". Any sequences of bytes representing
819
524
  a not-well-formed substring (according to cs) are hex-encoded,
820
525
  and all well-formed substrings (according to cs) are copied as is.
821
 
  Not more than "dstlen" bytes are written to "dst". The number 
 
526
  Not more than "dstlen" bytes are written to "dst". The number
822
527
  of bytes written to "dst" is returned.
823
 
  
 
528
 
824
529
   @param      cs       character set pointer of the destination string
825
530
   @param[out] dst      destination string
826
531
   @param      dstlen   size of dst
876
581
  copy a string,
877
582
  with optional character set conversion,
878
583
  with optional left padding (for binary -> UCS2 conversion)
879
 
  
 
584
 
880
585
  SYNOPSIS
881
586
    well_formed_copy_nchars()
882
587
    to                       Store result here
901
606
 
902
607
uint32_t
903
608
well_formed_copy_nchars(const CHARSET_INFO * const to_cs,
904
 
                        char *to, uint to_length,
 
609
                        char *to, uint32_t to_length,
905
610
                        const CHARSET_INFO * const from_cs,
906
 
                        const char *from, uint from_length,
907
 
                        uint nchars,
 
611
                        const char *from, uint32_t from_length,
 
612
                        uint32_t nchars,
908
613
                        const char **well_formed_error_pos,
909
614
                        const char **cannot_convert_error_pos,
910
615
                        const char **from_end_pos)
911
616
{
912
 
  uint res;
913
 
 
914
 
  if ((to_cs == &my_charset_bin) || 
915
 
      (from_cs == &my_charset_bin) ||
916
 
      (to_cs == from_cs) ||
917
 
      my_charset_same(from_cs, to_cs))
918
 
  {
919
 
    if (to_length < to_cs->mbminlen || !nchars)
920
 
    {
921
 
      *from_end_pos= from;
922
 
      *cannot_convert_error_pos= NULL;
923
 
      *well_formed_error_pos= NULL;
924
 
      return 0;
925
 
    }
926
 
 
927
 
    if (to_cs == &my_charset_bin)
928
 
    {
929
 
      res= min(min(nchars, to_length), from_length);
930
 
      memmove(to, from, res);
931
 
      *from_end_pos= from + res;
932
 
      *well_formed_error_pos= NULL;
933
 
      *cannot_convert_error_pos= NULL;
934
 
    }
935
 
    else
936
 
    {
937
 
      int well_formed_error;
938
 
      uint from_offset;
939
 
 
940
 
      if ((from_offset= (from_length % to_cs->mbminlen)) &&
941
 
          (from_cs == &my_charset_bin))
942
 
      {
943
 
        /*
944
 
          Copying from BINARY to UCS2 needs to prepend zeros sometimes:
945
 
          INSERT INTO t1 (ucs2_column) VALUES (0x01);
946
 
          0x01 -> 0x0001
947
 
        */
948
 
        uint pad_length= to_cs->mbminlen - from_offset;
949
 
        memset(to, 0, pad_length);
950
 
        memmove(to + pad_length, from, from_offset);
951
 
        nchars--;
952
 
        from+= from_offset;
953
 
        from_length-= from_offset;
954
 
        to+= to_cs->mbminlen;
955
 
        to_length-= to_cs->mbminlen;
956
 
      }
957
 
 
958
 
      set_if_smaller(from_length, to_length);
959
 
      res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
960
 
                                        nchars, &well_formed_error);
961
 
      memmove(to, from, res);
962
 
      *from_end_pos= from + res;
963
 
      *well_formed_error_pos= well_formed_error ? from + res : NULL;
964
 
      *cannot_convert_error_pos= NULL;
965
 
      if (from_offset)
966
 
        res+= to_cs->mbminlen;
967
 
    }
968
 
  }
969
 
  else
970
 
  {
971
 
    int cnvres;
972
 
    my_wc_t wc;
973
 
    my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
974
 
    my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
975
 
    const uchar *from_end= (const uchar*) from + from_length;
976
 
    uchar *to_end= (uchar*) to + to_length;
977
 
    char *to_start= to;
978
 
    *well_formed_error_pos= NULL;
979
 
    *cannot_convert_error_pos= NULL;
980
 
 
981
 
    for ( ; nchars; nchars--)
982
 
    {
983
 
      const char *from_prev= from;
984
 
      if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
985
 
        from+= cnvres;
986
 
      else if (cnvres == MY_CS_ILSEQ)
987
 
      {
988
 
        if (!*well_formed_error_pos)
989
 
          *well_formed_error_pos= from;
990
 
        from++;
991
 
        wc= '?';
992
 
      }
993
 
      else if (cnvres > MY_CS_TOOSMALL)
994
 
      {
995
 
        /*
996
 
          A correct multibyte sequence detected
997
 
          But it doesn't have Unicode mapping.
998
 
        */
999
 
        if (!*cannot_convert_error_pos)
1000
 
          *cannot_convert_error_pos= from;
1001
 
        from+= (-cnvres);
1002
 
        wc= '?';
1003
 
      }
1004
 
      else
1005
 
        break;  // Not enough characters
1006
 
 
1007
 
outp:
1008
 
      if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
1009
 
        to+= cnvres;
1010
 
      else if (cnvres == MY_CS_ILUNI && wc != '?')
1011
 
      {
1012
 
        if (!*cannot_convert_error_pos)
1013
 
          *cannot_convert_error_pos= from_prev;
1014
 
        wc= '?';
1015
 
        goto outp;
1016
 
      }
1017
 
      else
1018
 
      {
1019
 
        from= from_prev;
1020
 
        break;
1021
 
      }
1022
 
    }
 
617
  uint32_t res;
 
618
 
 
619
  assert((to_cs == &my_charset_bin) ||
 
620
         (from_cs == &my_charset_bin) ||
 
621
         (to_cs == from_cs) ||
 
622
         my_charset_same(from_cs, to_cs));
 
623
 
 
624
  if (to_length < to_cs->mbminlen || !nchars)
 
625
  {
1023
626
    *from_end_pos= from;
1024
 
    res= to - to_start;
1025
 
  }
1026
 
  return (uint32_t) res;
 
627
    *cannot_convert_error_pos= NULL;
 
628
    *well_formed_error_pos= NULL;
 
629
    return 0;
 
630
  }
 
631
 
 
632
  if (to_cs == &my_charset_bin)
 
633
  {
 
634
    res= min(min(nchars, to_length), from_length);
 
635
    memmove(to, from, res);
 
636
    *from_end_pos= from + res;
 
637
    *well_formed_error_pos= NULL;
 
638
    *cannot_convert_error_pos= NULL;
 
639
  }
 
640
  else
 
641
  {
 
642
    int well_formed_error;
 
643
    uint32_t from_offset;
 
644
 
 
645
    if ((from_offset= (from_length % to_cs->mbminlen)) &&
 
646
        (from_cs == &my_charset_bin))
 
647
    {
 
648
      /*
 
649
        Copying from BINARY to UCS2 needs to prepend zeros sometimes:
 
650
        INSERT INTO t1 (ucs2_column) VALUES (0x01);
 
651
        0x01 -> 0x0001
 
652
      */
 
653
      uint32_t pad_length= to_cs->mbminlen - from_offset;
 
654
      memset(to, 0, pad_length);
 
655
      memmove(to + pad_length, from, from_offset);
 
656
      nchars--;
 
657
      from+= from_offset;
 
658
      from_length-= from_offset;
 
659
      to+= to_cs->mbminlen;
 
660
      to_length-= to_cs->mbminlen;
 
661
    }
 
662
 
 
663
    set_if_smaller(from_length, to_length);
 
664
    res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
 
665
                                      nchars, &well_formed_error);
 
666
    memmove(to, from, res);
 
667
    *from_end_pos= from + res;
 
668
    *well_formed_error_pos= well_formed_error ? from + res : NULL;
 
669
    *cannot_convert_error_pos= NULL;
 
670
    if (from_offset)
 
671
      res+= to_cs->mbminlen;
 
672
  }
 
673
 
 
674
  return res;
1027
675
}
1028
676
 
1029
677
 
1034
682
  char *st= (char*)Ptr, *end= st+str_length;
1035
683
  for (; st < end; st++)
1036
684
  {
1037
 
    uchar c= *st;
 
685
    unsigned char c= *st;
1038
686
    switch (c)
1039
687
    {
1040
688
    case '\\':
1041
 
      str->append(STRING_WITH_LEN("\\\\"));
 
689
      str->append("\\\\", sizeof("\\\\")-1);
1042
690
      break;
1043
691
    case '\0':
1044
 
      str->append(STRING_WITH_LEN("\\0"));
 
692
      str->append("\\0", sizeof("\\0")-1);
1045
693
      break;
1046
694
    case '\'':
1047
 
      str->append(STRING_WITH_LEN("\\'"));
 
695
      str->append("\\'", sizeof("\\'")-1);
1048
696
      break;
1049
697
    case '\n':
1050
 
      str->append(STRING_WITH_LEN("\\n"));
 
698
      str->append("\\n", sizeof("\\n")-1);
1051
699
      break;
1052
700
    case '\r':
1053
 
      str->append(STRING_WITH_LEN("\\r"));
 
701
      str->append("\\r", sizeof("\\r")-1);
1054
702
      break;
1055
703
    case '\032': // Ctrl-Z
1056
 
      str->append(STRING_WITH_LEN("\\Z"));
 
704
      str->append("\\Z", sizeof("\\Z")-1);
1057
705
      break;
1058
706
    default:
1059
707
      str->append(c);
1061
709
  }
1062
710
}
1063
711
 
 
712
/*
 
713
  Quote the given identifier.
 
714
  If the given identifier is empty, it will be quoted.
 
715
 
 
716
  SYNOPSIS
 
717
  append_identifier()
 
718
  name                  the identifier to be appended
 
719
  name_length           length of the appending identifier
 
720
*/
 
721
 
 
722
/* Factor the extern out */
 
723
extern const CHARSET_INFO *system_charset_info, *files_charset_info;
 
724
 
 
725
void String::append_identifier(const char *name, uint32_t in_length)
 
726
{
 
727
  const char *name_end;
 
728
  char quote_char;
 
729
  int q= '`';
 
730
 
 
731
  /*
 
732
    The identifier must be quoted as it includes a quote character or
 
733
   it's a keyword
 
734
  */
 
735
 
 
736
  reserve(in_length*2 + 2);
 
737
  quote_char= (char) q;
 
738
  append(&quote_char, 1, system_charset_info);
 
739
 
 
740
  for (name_end= name+in_length ; name < name_end ; name+= in_length)
 
741
  {
 
742
    unsigned char chr= (unsigned char) *name;
 
743
    in_length= my_mbcharlen(system_charset_info, chr);
 
744
    /*
 
745
      my_mbcharlen can return 0 on a wrong multibyte
 
746
      sequence. It is possible when upgrading from 4.0,
 
747
      and identifier contains some accented characters.
 
748
      The manual says it does not work. So we'll just
 
749
      change length to 1 not to hang in the endless loop.
 
750
    */
 
751
    if (!in_length)
 
752
      in_length= 1;
 
753
    if (in_length == 1 && chr == (unsigned char) quote_char)
 
754
      append(&quote_char, 1, system_charset_info);
 
755
    append(name, in_length, system_charset_info);
 
756
  }
 
757
  append(&quote_char, 1, system_charset_info);
 
758
}
 
759
 
1064
760
 
1065
761
/*
1066
762
  Exchange state of this object and argument.
1074
770
 
1075
771
void String::swap(String &s)
1076
772
{
1077
 
  swap_variables(char *, Ptr, s.Ptr);
1078
 
  swap_variables(uint32_t, str_length, s.str_length);
1079
 
  swap_variables(uint32_t, Alloced_length, s.Alloced_length);
1080
 
  swap_variables(bool, alloced, s.alloced);
1081
 
  swap_variables(const CHARSET_INFO *, str_charset, s.str_charset);
1082
 
}
 
773
  std::swap(Ptr, s.Ptr);
 
774
  std::swap(str_length, s.str_length);
 
775
  std::swap(Alloced_length, s.Alloced_length);
 
776
  std::swap(alloced, s.alloced);
 
777
  std::swap(str_charset, s.str_charset);
 
778
}
 
779
 
 
780
 
 
781
bool operator==(const String &s1, const String &s2)
 
782
{
 
783
  return stringcmp(&s1,&s2) == 0;
 
784
}
 
785
 
 
786
bool operator!=(const String &s1, const String &s2)
 
787
{
 
788
  return !(s1 == s2);
 
789
}
 
790