~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

  • Committer: Monty Taylor
  • Date: 2009-03-18 18:45:23 UTC
  • mto: (950.1.1 mordred)
  • mto: This revision was merged to the branch mainline in revision 943.
  • Revision ID: mordred@inaugust.com-20090318184523-mfbjyj5wkipv4n3b
Moved big tests to big suite. Added make target "make test-big" to allow for easy running of the big tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
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(size_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<size_t>(strlen(str))),
74
 
    Alloced_length(0),
75
 
    alloced(false),
76
 
    str_charset(cs)
77
 
{ }
78
 
 
79
 
 
80
 
String::String(const char *str, size_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, size_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 mem_root->alloc_root(static_cast<size_t>(size));
110
 
}
111
 
 
112
 
String::~String() { free(); }
113
 
 
114
 
bool String::real_alloc(size_t arg_length)
 
38
bool String::real_alloc(uint32_t arg_length)
115
39
{
116
40
  arg_length=ALIGN_SIZE(arg_length+1);
117
41
  str_length=0;
118
42
  if (Alloced_length < arg_length)
119
43
  {
120
 
    if (Alloced_length > 0)
121
 
      free();
 
44
    free();
122
45
    if (!(Ptr=(char*) malloc(arg_length)))
123
46
      return true;
124
47
    Alloced_length=arg_length;
134
57
** (for C functions)
135
58
*/
136
59
 
137
 
bool String::realloc(size_t alloc_length)
 
60
bool String::realloc(uint32_t alloc_length)
138
61
{
139
 
  size_t len=ALIGN_SIZE(alloc_length+1);
 
62
  uint32_t len=ALIGN_SIZE(alloc_length+1);
140
63
  if (Alloced_length < len)
141
64
  {
142
65
    char *new_ptr;
168
91
 
169
92
bool String::set_int(int64_t num, bool unsigned_flag, const CHARSET_INFO * const cs)
170
93
{
171
 
  size_t l=20*cs->mbmaxlen+1;
 
94
  uint32_t l=20*cs->mbmaxlen+1;
172
95
  int base= unsigned_flag ? 10 : -10;
173
96
 
174
97
  if (alloc(l))
175
98
    return true;
176
 
  str_length=(size_t) (cs->cset->int64_t10_to_str)(cs,Ptr,l,base,num);
 
99
  str_length=(uint32_t) (cs->cset->int64_t10_to_str)(cs,Ptr,l,base,num);
177
100
  str_charset=cs;
178
101
  return false;
179
102
}
180
103
 
181
 
bool String::set_real(double num,size_t decimals, const CHARSET_INFO * const cs)
 
104
bool String::set_real(double num,uint32_t decimals, const CHARSET_INFO * const cs)
182
105
{
183
106
  char buff[FLOATING_POINT_BUFFER];
184
 
  size_t dummy_errors;
 
107
  uint32_t dummy_errors;
185
108
  size_t len;
186
109
 
187
110
  str_charset=cs;
188
111
  if (decimals >= NOT_FIXED_DEC)
189
112
  {
190
 
    len= internal::my_gcvt(num,
191
 
                           internal::MY_GCVT_ARG_DOUBLE,
192
 
                           sizeof(buff) - 1, buff, NULL);
 
113
    len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
193
114
    return copy(buff, len, &my_charset_utf8_general_ci, cs, &dummy_errors);
194
115
  }
195
 
  len= internal::my_fcvt(num, decimals, buff, NULL);
196
 
  return copy(buff, (size_t) len, &my_charset_utf8_general_ci, cs,
 
116
  len= my_fcvt(num, decimals, buff, NULL);
 
117
  return copy(buff, (uint32_t) len, &my_charset_utf8_general_ci, cs,
197
118
              &dummy_errors);
198
119
}
199
120
 
219
140
  return false;
220
141
}
221
142
 
222
 
bool String::copy(const std::string& arg, const CHARSET_INFO * const cs)        // Allocate new string
223
 
{
224
 
  if (alloc(arg.size()))
225
 
    return true;
226
 
 
227
 
  if ((str_length= arg.size()))
228
 
    memcpy(Ptr, arg.c_str(), arg.size());
229
 
 
230
 
  Ptr[arg.size()]= 0;
231
 
  str_charset= cs;
232
 
 
233
 
  return false;
234
 
}
235
 
 
236
 
bool String::copy(const char *str,size_t arg_length, const CHARSET_INFO * const cs)
 
143
bool String::copy(const char *str,uint32_t arg_length, const CHARSET_INFO * const cs)
237
144
{
238
145
  if (alloc(arg_length))
239
146
    return true;
244
151
  return false;
245
152
}
246
153
 
 
154
 
247
155
/*
248
156
  Checks that the source string can be just copied to the destination string
249
157
  without conversion.
254
162
  arg_length            Length of string to copy.
255
163
  from_cs               Character set to copy from
256
164
  to_cs                 Character set to copy to
257
 
  size_t *offset        Returns number of unaligned characters.
 
165
  uint32_t *offset      Returns number of unaligned characters.
258
166
 
259
167
  RETURN
260
168
   0  No conversion needed
266
174
  character_set_results is NULL.
267
175
*/
268
176
 
269
 
bool String::needs_conversion(size_t arg_length,
 
177
bool String::needs_conversion(uint32_t arg_length,
270
178
                              const CHARSET_INFO * const from_cs,
271
179
                              const CHARSET_INFO * const to_cs,
272
 
                              size_t *offset)
 
180
                              uint32_t *offset)
273
181
{
274
182
  *offset= 0;
275
183
  if (!to_cs ||
285
193
 
286
194
 
287
195
 
288
 
bool String::set_or_copy_aligned(const char *str,size_t arg_length,
 
196
bool String::set_or_copy_aligned(const char *str,uint32_t arg_length,
289
197
                                 const CHARSET_INFO * const cs)
290
198
{
291
199
  /* How many bytes are in incomplete character */
292
 
  size_t offset= (arg_length % cs->mbminlen);
 
200
  uint32_t offset= (arg_length % cs->mbminlen);
293
201
 
294
202
  assert(!offset); /* All characters are complete, just copy */
295
203
 
299
207
 
300
208
        /* Copy with charset conversion */
301
209
 
302
 
bool String::copy(const char *str, size_t arg_length,
303
 
                          const CHARSET_INFO * const,
304
 
                                  const CHARSET_INFO * const to_cs, size_t *errors)
 
210
bool String::copy(const char *str, uint32_t arg_length,
 
211
                          const CHARSET_INFO * const from_cs,
 
212
                                  const CHARSET_INFO * const to_cs, uint32_t *errors)
305
213
{
306
 
  *errors= 0;
307
 
  return copy(str, arg_length, to_cs);
 
214
  uint32_t offset;
 
215
  if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
 
216
  {
 
217
    *errors= 0;
 
218
    return copy(str, arg_length, to_cs);
 
219
  }
 
220
  if ((from_cs == &my_charset_bin) && offset)
 
221
  {
 
222
    *errors= 0;
 
223
    assert((from_cs == &my_charset_bin) && offset);
 
224
    return false; //copy_aligned(str, arg_length, offset, to_cs);
 
225
  }
 
226
  uint32_t new_length= to_cs->mbmaxlen*arg_length;
 
227
  if (alloc(new_length))
 
228
    return true;
 
229
  str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
 
230
                              str, arg_length, from_cs, errors);
 
231
  str_charset=to_cs;
 
232
  return false;
308
233
}
309
234
 
310
235
 
327
252
 
328
253
*/
329
254
 
330
 
bool String::set_ascii(const char *str, size_t arg_length)
 
255
bool String::set_ascii(const char *str, uint32_t arg_length)
331
256
{
332
257
  if (str_charset->mbminlen == 1)
333
258
  {
334
259
    set(str, arg_length, str_charset);
335
260
    return 0;
336
261
  }
337
 
  size_t dummy_errors;
 
262
  uint32_t dummy_errors;
338
263
  return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
339
264
}
340
265
 
355
280
  Append an ASCII string to the a string of the current character set
356
281
*/
357
282
 
358
 
bool String::append(const char *s,size_t arg_length)
 
283
bool String::append(const char *s,uint32_t arg_length)
359
284
{
360
285
  if (!arg_length)
361
286
    return false;
362
287
 
363
288
  /*
 
289
    For an ASCII incompatible string, e.g. UCS-2, we need to convert
 
290
  */
 
291
  if (str_charset->mbminlen > 1)
 
292
  {
 
293
    uint32_t add_length=arg_length * str_charset->mbmaxlen;
 
294
    uint32_t dummy_errors;
 
295
    if (realloc(str_length+ add_length))
 
296
      return true;
 
297
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
298
                                  s, arg_length, &my_charset_utf8_general_ci,
 
299
                                  &dummy_errors);
 
300
    return false;
 
301
  }
 
302
 
 
303
  /*
364
304
    For an ASCII compatinble string we can just append.
365
305
  */
366
306
  if (realloc(str_length+arg_length))
386
326
  with character set recoding
387
327
*/
388
328
 
389
 
bool String::append(const char *s,size_t arg_length, const CHARSET_INFO * const)
 
329
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const cs)
390
330
{
391
 
  if (realloc(str_length + arg_length))
392
 
    return true;
393
 
  memcpy(Ptr + str_length, s, arg_length);
394
 
  str_length+= arg_length;
 
331
  uint32_t dummy_offset;
395
332
 
 
333
  if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
 
334
  {
 
335
    uint32_t add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
 
336
    uint32_t dummy_errors;
 
337
    if (realloc(str_length + add_length))
 
338
      return true;
 
339
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
340
                                  s, arg_length, cs, &dummy_errors);
 
341
  }
 
342
  else
 
343
  {
 
344
    if (realloc(str_length + arg_length))
 
345
      return true;
 
346
    memcpy(Ptr + str_length, s, arg_length);
 
347
    str_length+= arg_length;
 
348
  }
396
349
  return false;
397
350
}
398
351
 
399
352
 
400
 
bool String::append_with_prefill(const char *s,size_t arg_length,
401
 
                 size_t full_length, char fill_char)
 
353
bool String::append_with_prefill(const char *s,uint32_t arg_length,
 
354
                 uint32_t full_length, char fill_char)
402
355
{
403
356
  int t_length= arg_length > full_length ? arg_length : full_length;
404
357
 
414
367
  return false;
415
368
}
416
369
 
417
 
size_t String::numchars()
 
370
uint32_t String::numchars()
418
371
{
419
372
  return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
420
373
}
421
374
 
422
 
int String::charpos(int i,size_t offset)
 
375
int String::charpos(int i,uint32_t offset)
423
376
{
424
377
  if (i <= 0)
425
378
    return i;
426
379
  return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
427
380
}
428
381
 
429
 
int String::strstr(const String &s,size_t offset)
 
382
int String::strstr(const String &s,uint32_t offset)
430
383
{
431
384
  if (s.length()+offset <= str_length)
432
385
  {
457
410
** Search string from end. Offset is offset to the end of string
458
411
*/
459
412
 
460
 
int String::strrstr(const String &s,size_t offset)
 
413
int String::strrstr(const String &s,uint32_t offset)
461
414
{
462
415
  if (s.length() <= offset && offset <= str_length)
463
416
  {
489
442
  If wrong parameter or not enough memory, do nothing
490
443
*/
491
444
 
492
 
bool String::replace(size_t offset,size_t arg_length,const String &to)
 
445
bool String::replace(uint32_t offset,uint32_t arg_length,const String &to)
493
446
{
494
447
  return replace(offset,arg_length,to.ptr(),to.length());
495
448
}
496
449
 
497
 
bool String::replace(size_t offset,size_t arg_length,
498
 
                     const char *to, size_t to_length)
 
450
bool String::replace(uint32_t offset,uint32_t arg_length,
 
451
                     const char *to, uint32_t to_length)
499
452
{
500
453
  long diff = (long) to_length-(long) arg_length;
501
454
  if (offset+arg_length <= str_length)
511
464
    {
512
465
      if (diff)
513
466
      {
514
 
        if (realloc(str_length+(size_t) diff))
 
467
        if (realloc(str_length+(uint32_t) diff))
515
468
          return true;
516
 
        internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
517
 
                            (unsigned char*) Ptr+str_length,
518
 
                            str_length-offset-arg_length);
 
469
        bmove_upp((unsigned char*) Ptr+str_length+diff, (unsigned char*) Ptr+str_length,
 
470
                  str_length-offset-arg_length);
519
471
      }
520
472
      if (to_length)
521
473
        memcpy(Ptr+offset,to,to_length);
522
474
    }
523
 
    str_length+=(size_t) diff;
 
475
    str_length+=(uint32_t) diff;
524
476
  }
525
477
  return false;
526
478
}
574
526
 
575
527
int stringcmp(const String *s,const String *t)
576
528
{
577
 
  size_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
 
529
  uint32_t s_len=s->length(),t_len=t->length(),len=cmin(s_len,t_len);
578
530
  int cmp= memcmp(s->ptr(), t->ptr(), len);
579
531
  return (cmp) ? cmp : (int) (s_len - t_len);
580
532
}
581
533
 
582
534
 
583
 
String *copy_if_not_alloced(String *to,String *from,size_t from_length)
 
535
String *copy_if_not_alloced(String *to,String *from,uint32_t from_length)
584
536
{
585
537
  if (from->Alloced_length >= from_length)
586
538
    return from;
591
543
  }
592
544
  if (to->realloc(from_length))
593
545
    return from;                                // Actually an error
594
 
  if ((to->str_length= min(from->str_length,from_length)))
 
546
  if ((to->str_length=cmin(from->str_length,from_length)))
595
547
    memcpy(to->Ptr,from->Ptr,to->str_length);
596
548
  to->str_charset=from->str_charset;
597
549
  return to;
603
555
****************************************************************************/
604
556
 
605
557
/*
 
558
  copy a string from one character set to another
 
559
 
 
560
  SYNOPSIS
 
561
    copy_and_convert()
 
562
    to                  Store result here
 
563
    to_cs               Character set of result string
 
564
    from                Copy from here
 
565
    from_length         Length of from string
 
566
    from_cs             From character set
 
567
 
 
568
  NOTES
 
569
    'to' must be big enough as form_length * to_cs->mbmaxlen
 
570
 
 
571
  RETURN
 
572
    length of bytes copied to 'to'
 
573
*/
 
574
 
 
575
 
 
576
static uint32_t
 
577
copy_and_convert_extended(char *to, uint32_t to_length,
 
578
                          const CHARSET_INFO * const to_cs,
 
579
                          const char *from, uint32_t from_length,
 
580
                          const CHARSET_INFO * const from_cs,
 
581
                          uint32_t *errors)
 
582
{
 
583
  int         cnvres;
 
584
  my_wc_t     wc;
 
585
  const unsigned char *from_end= (const unsigned char*) from+from_length;
 
586
  char *to_start= to;
 
587
  unsigned char *to_end= (unsigned char*) to+to_length;
 
588
  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
589
  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
590
  uint32_t error_count= 0;
 
591
 
 
592
  while (1)
 
593
  {
 
594
    if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from,
 
595
                                      from_end)) > 0)
 
596
      from+= cnvres;
 
597
    else if (cnvres == MY_CS_ILSEQ)
 
598
    {
 
599
      error_count++;
 
600
      from++;
 
601
      wc= '?';
 
602
    }
 
603
    else if (cnvres > MY_CS_TOOSMALL)
 
604
    {
 
605
      /*
 
606
        A correct multibyte sequence detected
 
607
        But it doesn't have Unicode mapping.
 
608
      */
 
609
      error_count++;
 
610
      from+= (-cnvres);
 
611
      wc= '?';
 
612
    }
 
613
    else
 
614
      break;  // Not enough characters
 
615
 
 
616
outp:
 
617
    if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
618
      to+= cnvres;
 
619
    else if (cnvres == MY_CS_ILUNI && wc != '?')
 
620
    {
 
621
      error_count++;
 
622
      wc= '?';
 
623
      goto outp;
 
624
    }
 
625
    else
 
626
      break;
 
627
  }
 
628
  *errors= error_count;
 
629
  return (uint32_t) (to - to_start);
 
630
}
 
631
 
 
632
 
 
633
/*
 
634
  Optimized for quick copying of ASCII characters in the range 0x00..0x7F.
 
635
*/
 
636
uint32_t
 
637
copy_and_convert(char *to, uint32_t to_length, const CHARSET_INFO * const to_cs,
 
638
                 const char *from, uint32_t from_length,
 
639
                                 const CHARSET_INFO * const from_cs, uint32_t *errors)
 
640
{
 
641
  /*
 
642
    If any of the character sets is not ASCII compatible,
 
643
    immediately switch to slow mb_wc->wc_mb method.
 
644
  */
 
645
  if ((to_cs->state | from_cs->state) & MY_CS_NONASCII)
 
646
    return copy_and_convert_extended(to, to_length, to_cs,
 
647
                                     from, from_length, from_cs, errors);
 
648
 
 
649
  uint32_t length= cmin(to_length, from_length), length2= length;
 
650
 
 
651
#if defined(__i386__)
 
652
  /*
 
653
    Special loop for i386, it allows to refer to a
 
654
    non-aligned memory block as UINT32, which makes
 
655
    it possible to copy four bytes at once. This
 
656
    gives about 10% performance improvement comparing
 
657
    to byte-by-byte loop.
 
658
  */
 
659
  for ( ; length >= 4; length-= 4, from+= 4, to+= 4)
 
660
  {
 
661
    if ((*(uint32_t*)from) & 0x80808080)
 
662
      break;
 
663
    *((uint32_t*) to)= *((const uint32_t*) from);
 
664
  }
 
665
#endif
 
666
 
 
667
  for (; ; *to++= *from++, length--)
 
668
  {
 
669
    if (!length)
 
670
    {
 
671
      *errors= 0;
 
672
      return length2;
 
673
    }
 
674
    if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */
 
675
    {
 
676
      uint32_t copied_length= length2 - length;
 
677
      to_length-= copied_length;
 
678
      from_length-= copied_length;
 
679
      return copied_length + copy_and_convert_extended(to, to_length,
 
680
                                                       to_cs,
 
681
                                                       from, from_length,
 
682
                                                       from_cs,
 
683
                                                       errors);
 
684
    }
 
685
  }
 
686
 
 
687
#ifndef __sun
 
688
  return 0;           // Make compiler happy
 
689
#endif
 
690
}
 
691
 
 
692
 
 
693
/**
 
694
  Copy string with HEX-encoding of "bad" characters.
 
695
 
 
696
  @details This functions copies the string pointed by "src"
 
697
  to the string pointed by "dst". Not more than "srclen" bytes
 
698
  are read from "src". Any sequences of bytes representing
 
699
  a not-well-formed substring (according to cs) are hex-encoded,
 
700
  and all well-formed substrings (according to cs) are copied as is.
 
701
  Not more than "dstlen" bytes are written to "dst". The number
 
702
  of bytes written to "dst" is returned.
 
703
 
 
704
   @param      cs       character set pointer of the destination string
 
705
   @param[out] dst      destination string
 
706
   @param      dstlen   size of dst
 
707
   @param      src      source string
 
708
   @param      srclen   length of src
 
709
 
 
710
   @retval     result length
 
711
*/
 
712
 
 
713
size_t
 
714
my_copy_with_hex_escaping(const CHARSET_INFO * const cs,
 
715
                          char *dst, size_t dstlen,
 
716
                          const char *src, size_t srclen)
 
717
{
 
718
  const char *srcend= src + srclen;
 
719
  char *dst0= dst;
 
720
 
 
721
  for ( ; src < srcend ; )
 
722
  {
 
723
    size_t chlen;
 
724
    if ((chlen= my_ismbchar(cs, src, srcend)))
 
725
    {
 
726
      if (dstlen < chlen)
 
727
        break; /* purecov: inspected */
 
728
      memcpy(dst, src, chlen);
 
729
      src+= chlen;
 
730
      dst+= chlen;
 
731
      dstlen-= chlen;
 
732
    }
 
733
    else if (*src & 0x80)
 
734
    {
 
735
      if (dstlen < 4)
 
736
        break; /* purecov: inspected */
 
737
      *dst++= '\\';
 
738
      *dst++= 'x';
 
739
      *dst++= _dig_vec_upper[((unsigned char) *src) >> 4];
 
740
      *dst++= _dig_vec_upper[((unsigned char) *src) & 15];
 
741
      src++;
 
742
      dstlen-= 4;
 
743
    }
 
744
    else
 
745
    {
 
746
      if (dstlen < 1)
 
747
        break; /* purecov: inspected */
 
748
      *dst++= *src++;
 
749
      dstlen--;
 
750
    }
 
751
  }
 
752
  return dst - dst0;
 
753
}
 
754
 
 
755
/*
606
756
  copy a string,
607
757
  with optional character set conversion,
608
758
  with optional left padding (for binary -> UCS2 conversion)
629
779
*/
630
780
 
631
781
 
632
 
size_t
 
782
uint32_t
633
783
well_formed_copy_nchars(const CHARSET_INFO * const to_cs,
634
 
                        char *to, size_t to_length,
 
784
                        char *to, uint32_t to_length,
635
785
                        const CHARSET_INFO * const from_cs,
636
 
                        const char *from, size_t from_length,
637
 
                        size_t nchars,
 
786
                        const char *from, uint32_t from_length,
 
787
                        uint32_t nchars,
638
788
                        const char **well_formed_error_pos,
639
789
                        const char **cannot_convert_error_pos,
640
790
                        const char **from_end_pos)
641
791
{
642
 
  size_t res;
643
 
 
644
 
  assert((to_cs == &my_charset_bin) ||
645
 
         (from_cs == &my_charset_bin) ||
646
 
         (to_cs == from_cs) ||
647
 
         my_charset_same(from_cs, to_cs));
648
 
 
649
 
  if (to_length < to_cs->mbminlen || !nchars)
650
 
  {
 
792
  uint32_t res;
 
793
 
 
794
  if ((to_cs == &my_charset_bin) ||
 
795
      (from_cs == &my_charset_bin) ||
 
796
      (to_cs == from_cs) ||
 
797
      my_charset_same(from_cs, to_cs))
 
798
  {
 
799
    if (to_length < to_cs->mbminlen || !nchars)
 
800
    {
 
801
      *from_end_pos= from;
 
802
      *cannot_convert_error_pos= NULL;
 
803
      *well_formed_error_pos= NULL;
 
804
      return 0;
 
805
    }
 
806
 
 
807
    if (to_cs == &my_charset_bin)
 
808
    {
 
809
      res= cmin(cmin(nchars, to_length), from_length);
 
810
      memmove(to, from, res);
 
811
      *from_end_pos= from + res;
 
812
      *well_formed_error_pos= NULL;
 
813
      *cannot_convert_error_pos= NULL;
 
814
    }
 
815
    else
 
816
    {
 
817
      int well_formed_error;
 
818
      uint32_t from_offset;
 
819
 
 
820
      if ((from_offset= (from_length % to_cs->mbminlen)) &&
 
821
          (from_cs == &my_charset_bin))
 
822
      {
 
823
        /*
 
824
          Copying from BINARY to UCS2 needs to prepend zeros sometimes:
 
825
          INSERT INTO t1 (ucs2_column) VALUES (0x01);
 
826
          0x01 -> 0x0001
 
827
        */
 
828
        uint32_t pad_length= to_cs->mbminlen - from_offset;
 
829
        memset(to, 0, pad_length);
 
830
        memmove(to + pad_length, from, from_offset);
 
831
        nchars--;
 
832
        from+= from_offset;
 
833
        from_length-= from_offset;
 
834
        to+= to_cs->mbminlen;
 
835
        to_length-= to_cs->mbminlen;
 
836
      }
 
837
 
 
838
      set_if_smaller(from_length, to_length);
 
839
      res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
 
840
                                        nchars, &well_formed_error);
 
841
      memmove(to, from, res);
 
842
      *from_end_pos= from + res;
 
843
      *well_formed_error_pos= well_formed_error ? from + res : NULL;
 
844
      *cannot_convert_error_pos= NULL;
 
845
      if (from_offset)
 
846
        res+= to_cs->mbminlen;
 
847
    }
 
848
  }
 
849
  else
 
850
  {
 
851
    int cnvres;
 
852
    my_wc_t wc;
 
853
    my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
854
    my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
855
    const unsigned char *from_end= (const unsigned char*) from + from_length;
 
856
    unsigned char *to_end= (unsigned char*) to + to_length;
 
857
    char *to_start= to;
 
858
    *well_formed_error_pos= NULL;
 
859
    *cannot_convert_error_pos= NULL;
 
860
 
 
861
    for ( ; nchars; nchars--)
 
862
    {
 
863
      const char *from_prev= from;
 
864
      if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from, from_end)) > 0)
 
865
        from+= cnvres;
 
866
      else if (cnvres == MY_CS_ILSEQ)
 
867
      {
 
868
        if (!*well_formed_error_pos)
 
869
          *well_formed_error_pos= from;
 
870
        from++;
 
871
        wc= '?';
 
872
      }
 
873
      else if (cnvres > MY_CS_TOOSMALL)
 
874
      {
 
875
        /*
 
876
          A correct multibyte sequence detected
 
877
          But it doesn't have Unicode mapping.
 
878
        */
 
879
        if (!*cannot_convert_error_pos)
 
880
          *cannot_convert_error_pos= from;
 
881
        from+= (-cnvres);
 
882
        wc= '?';
 
883
      }
 
884
      else
 
885
        break;  // Not enough characters
 
886
 
 
887
outp:
 
888
      if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
889
        to+= cnvres;
 
890
      else if (cnvres == MY_CS_ILUNI && wc != '?')
 
891
      {
 
892
        if (!*cannot_convert_error_pos)
 
893
          *cannot_convert_error_pos= from_prev;
 
894
        wc= '?';
 
895
        goto outp;
 
896
      }
 
897
      else
 
898
      {
 
899
        from= from_prev;
 
900
        break;
 
901
      }
 
902
    }
651
903
    *from_end_pos= from;
652
 
    *cannot_convert_error_pos= NULL;
653
 
    *well_formed_error_pos= NULL;
654
 
    return 0;
655
 
  }
656
 
 
657
 
  if (to_cs == &my_charset_bin)
658
 
  {
659
 
    res= min(min(nchars, to_length), from_length);
660
 
    memmove(to, from, res);
661
 
    *from_end_pos= from + res;
662
 
    *well_formed_error_pos= NULL;
663
 
    *cannot_convert_error_pos= NULL;
664
 
  }
665
 
  else
666
 
  {
667
 
    int well_formed_error;
668
 
    size_t from_offset;
669
 
 
670
 
    if ((from_offset= (from_length % to_cs->mbminlen)) &&
671
 
        (from_cs == &my_charset_bin))
672
 
    {
673
 
      /*
674
 
        Copying from BINARY to UCS2 needs to prepend zeros sometimes:
675
 
        INSERT INTO t1 (ucs2_column) VALUES (0x01);
676
 
        0x01 -> 0x0001
677
 
      */
678
 
      size_t pad_length= to_cs->mbminlen - from_offset;
679
 
      memset(to, 0, pad_length);
680
 
      memmove(to + pad_length, from, from_offset);
681
 
      nchars--;
682
 
      from+= from_offset;
683
 
      from_length-= from_offset;
684
 
      to+= to_cs->mbminlen;
685
 
      to_length-= to_cs->mbminlen;
686
 
    }
687
 
 
688
 
    set_if_smaller(from_length, to_length);
689
 
    res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
690
 
                                      nchars, &well_formed_error);
691
 
    memmove(to, from, res);
692
 
    *from_end_pos= from + res;
693
 
    *well_formed_error_pos= well_formed_error ? from + res : NULL;
694
 
    *cannot_convert_error_pos= NULL;
695
 
    if (from_offset)
696
 
      res+= to_cs->mbminlen;
697
 
  }
698
 
 
699
 
  return res;
 
904
    res= to - to_start;
 
905
  }
 
906
  return (uint32_t) res;
700
907
}
701
908
 
702
909
 
747
954
/* Factor the extern out */
748
955
extern const CHARSET_INFO *system_charset_info, *files_charset_info;
749
956
 
750
 
void String::append_identifier(const char *name, size_t in_length)
 
957
void String::append_identifier(const char *name, uint32_t in_length)
751
958
{
752
959
  const char *name_end;
753
960
  char quote_char;
802
1009
  std::swap(str_charset, s.str_charset);
803
1010
}
804
1011
 
805
 
void String::q_append(const size_t n)
806
 
{
807
 
  int8store(Ptr + str_length, n);
808
 
  str_length += 4;
809
 
}
810
 
void String::q_append(double d)
811
 
{
812
 
  float8store(Ptr + str_length, d);
813
 
  str_length += 8;
814
 
}
815
 
void String::q_append(double *d)
816
 
{
817
 
  float8store(Ptr + str_length, *d);
818
 
  str_length += 8;
819
 
}
820
 
void String::q_append(const char *data, size_t data_len)
821
 
{
822
 
  memcpy(Ptr + str_length, data, data_len);
823
 
  str_length += data_len;
824
 
}
825
 
 
826
 
void String::write_at_position(int position, size_t value)
827
 
{
828
 
  int8store(Ptr + position,value);
829
 
}
830
 
bool check_if_only_end_space(const CHARSET_INFO * const cs, char *str,
831
 
                             char *end)
832
 
{
833
 
  return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
834
 
}
835
 
 
836
 
std::ostream& operator<<(std::ostream& output, const String &str)
837
 
{
838
 
  output << "String:(";
839
 
  output <<  const_cast<String&>(str).c_str();
840
 
  output << ", ";
841
 
  output << str.length();
842
 
  output << ")";
843
 
 
844
 
  return output;  // for multiple << operators.
845
 
}
846
 
 
847
 
} /* namespace drizzled */
848
 
 
849
 
bool operator==(const drizzled::String &s1, const drizzled::String &s2)
 
1012
 
 
1013
bool operator==(const String &s1, const String &s2)
850
1014
{
851
1015
  return stringcmp(&s1,&s2) == 0;
852
1016
}
853
1017
 
854
 
bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
 
1018
bool operator!=(const String &s1, const String &s2)
855
1019
{
856
1020
  return !(s1 == s2);
857
1021
}