~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

Merge Monty.

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