~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

  • Committer: Jay Pipes
  • Date: 2009-03-13 23:35:46 UTC
  • mto: This revision was merged to the branch mainline in revision 937.
  • Revision ID: jpipes@serialcoder-20090313233546-n12t6xpf71um75fo
Split index hints out into their own file, removal from sql_lex.h and sql_select.cc

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 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)
223
144
{
224
145
  if (alloc(arg_length))
225
146
    return true;
230
151
  return false;
231
152
}
232
153
 
 
154
 
233
155
/*
234
156
  Checks that the source string can be just copied to the destination string
235
157
  without conversion.
240
162
  arg_length            Length of string to copy.
241
163
  from_cs               Character set to copy from
242
164
  to_cs                 Character set to copy to
243
 
  size_t *offset        Returns number of unaligned characters.
 
165
  uint32_t *offset      Returns number of unaligned characters.
244
166
 
245
167
  RETURN
246
168
   0  No conversion needed
252
174
  character_set_results is NULL.
253
175
*/
254
176
 
255
 
bool String::needs_conversion(size_t arg_length,
 
177
bool String::needs_conversion(uint32_t arg_length,
256
178
                              const CHARSET_INFO * const from_cs,
257
179
                              const CHARSET_INFO * const to_cs,
258
 
                              size_t *offset)
 
180
                              uint32_t *offset)
259
181
{
260
182
  *offset= 0;
261
183
  if (!to_cs ||
271
193
 
272
194
 
273
195
 
274
 
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,
275
197
                                 const CHARSET_INFO * const cs)
276
198
{
277
199
  /* How many bytes are in incomplete character */
278
 
  size_t offset= (arg_length % cs->mbminlen);
 
200
  uint32_t offset= (arg_length % cs->mbminlen);
279
201
 
280
202
  assert(!offset); /* All characters are complete, just copy */
281
203
 
285
207
 
286
208
        /* Copy with charset conversion */
287
209
 
288
 
bool String::copy(const char *str, size_t arg_length,
289
 
                          const CHARSET_INFO * const,
290
 
                                  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)
291
213
{
292
 
  *errors= 0;
293
 
  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;
294
233
}
295
234
 
296
235
 
313
252
 
314
253
*/
315
254
 
316
 
bool String::set_ascii(const char *str, size_t arg_length)
 
255
bool String::set_ascii(const char *str, uint32_t arg_length)
317
256
{
318
257
  if (str_charset->mbminlen == 1)
319
258
  {
320
259
    set(str, arg_length, str_charset);
321
260
    return 0;
322
261
  }
323
 
  size_t dummy_errors;
 
262
  uint32_t dummy_errors;
324
263
  return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
325
264
}
326
265
 
341
280
  Append an ASCII string to the a string of the current character set
342
281
*/
343
282
 
344
 
bool String::append(const char *s,size_t arg_length)
 
283
bool String::append(const char *s,uint32_t arg_length)
345
284
{
346
285
  if (!arg_length)
347
286
    return false;
348
287
 
349
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
  /*
350
304
    For an ASCII compatinble string we can just append.
351
305
  */
352
306
  if (realloc(str_length+arg_length))
372
326
  with character set recoding
373
327
*/
374
328
 
375
 
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)
376
330
{
377
 
  if (realloc(str_length + arg_length))
378
 
    return true;
379
 
  memcpy(Ptr + str_length, s, arg_length);
380
 
  str_length+= arg_length;
 
331
  uint32_t dummy_offset;
381
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
  }
382
349
  return false;
383
350
}
384
351
 
385
352
 
386
 
bool String::append_with_prefill(const char *s,size_t arg_length,
387
 
                 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)
388
355
{
389
356
  int t_length= arg_length > full_length ? arg_length : full_length;
390
357
 
400
367
  return false;
401
368
}
402
369
 
403
 
size_t String::numchars()
 
370
uint32_t String::numchars()
404
371
{
405
372
  return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
406
373
}
407
374
 
408
 
int String::charpos(int i,size_t offset)
 
375
int String::charpos(int i,uint32_t offset)
409
376
{
410
377
  if (i <= 0)
411
378
    return i;
412
379
  return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
413
380
}
414
381
 
415
 
int String::strstr(const String &s,size_t offset)
 
382
int String::strstr(const String &s,uint32_t offset)
416
383
{
417
384
  if (s.length()+offset <= str_length)
418
385
  {
443
410
** Search string from end. Offset is offset to the end of string
444
411
*/
445
412
 
446
 
int String::strrstr(const String &s,size_t offset)
 
413
int String::strrstr(const String &s,uint32_t offset)
447
414
{
448
415
  if (s.length() <= offset && offset <= str_length)
449
416
  {
475
442
  If wrong parameter or not enough memory, do nothing
476
443
*/
477
444
 
478
 
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)
479
446
{
480
447
  return replace(offset,arg_length,to.ptr(),to.length());
481
448
}
482
449
 
483
 
bool String::replace(size_t offset,size_t arg_length,
484
 
                     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)
485
452
{
486
453
  long diff = (long) to_length-(long) arg_length;
487
454
  if (offset+arg_length <= str_length)
497
464
    {
498
465
      if (diff)
499
466
      {
500
 
        if (realloc(str_length+(size_t) diff))
 
467
        if (realloc(str_length+(uint32_t) diff))
501
468
          return true;
502
 
        internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
503
 
                            (unsigned char*) Ptr+str_length,
504
 
                            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);
505
471
      }
506
472
      if (to_length)
507
473
        memcpy(Ptr+offset,to,to_length);
508
474
    }
509
 
    str_length+=(size_t) diff;
 
475
    str_length+=(uint32_t) diff;
510
476
  }
511
477
  return false;
512
478
}
560
526
 
561
527
int stringcmp(const String *s,const String *t)
562
528
{
563
 
  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);
564
530
  int cmp= memcmp(s->ptr(), t->ptr(), len);
565
531
  return (cmp) ? cmp : (int) (s_len - t_len);
566
532
}
567
533
 
568
534
 
569
 
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)
570
536
{
571
537
  if (from->Alloced_length >= from_length)
572
538
    return from;
577
543
  }
578
544
  if (to->realloc(from_length))
579
545
    return from;                                // Actually an error
580
 
  if ((to->str_length= min(from->str_length,from_length)))
 
546
  if ((to->str_length=cmin(from->str_length,from_length)))
581
547
    memcpy(to->Ptr,from->Ptr,to->str_length);
582
548
  to->str_charset=from->str_charset;
583
549
  return to;
589
555
****************************************************************************/
590
556
 
591
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
/*
592
756
  copy a string,
593
757
  with optional character set conversion,
594
758
  with optional left padding (for binary -> UCS2 conversion)
615
779
*/
616
780
 
617
781
 
618
 
size_t
 
782
uint32_t
619
783
well_formed_copy_nchars(const CHARSET_INFO * const to_cs,
620
 
                        char *to, size_t to_length,
 
784
                        char *to, uint32_t to_length,
621
785
                        const CHARSET_INFO * const from_cs,
622
 
                        const char *from, size_t from_length,
623
 
                        size_t nchars,
 
786
                        const char *from, uint32_t from_length,
 
787
                        uint32_t nchars,
624
788
                        const char **well_formed_error_pos,
625
789
                        const char **cannot_convert_error_pos,
626
790
                        const char **from_end_pos)
627
791
{
628
 
  size_t res;
629
 
 
630
 
  assert((to_cs == &my_charset_bin) ||
631
 
         (from_cs == &my_charset_bin) ||
632
 
         (to_cs == from_cs) ||
633
 
         my_charset_same(from_cs, to_cs));
634
 
 
635
 
  if (to_length < to_cs->mbminlen || !nchars)
636
 
  {
 
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
    }
637
903
    *from_end_pos= from;
638
 
    *cannot_convert_error_pos= NULL;
639
 
    *well_formed_error_pos= NULL;
640
 
    return 0;
641
 
  }
642
 
 
643
 
  if (to_cs == &my_charset_bin)
644
 
  {
645
 
    res= min(min(nchars, to_length), from_length);
646
 
    memmove(to, from, res);
647
 
    *from_end_pos= from + res;
648
 
    *well_formed_error_pos= NULL;
649
 
    *cannot_convert_error_pos= NULL;
650
 
  }
651
 
  else
652
 
  {
653
 
    int well_formed_error;
654
 
    size_t from_offset;
655
 
 
656
 
    if ((from_offset= (from_length % to_cs->mbminlen)) &&
657
 
        (from_cs == &my_charset_bin))
658
 
    {
659
 
      /*
660
 
        Copying from BINARY to UCS2 needs to prepend zeros sometimes:
661
 
        INSERT INTO t1 (ucs2_column) VALUES (0x01);
662
 
        0x01 -> 0x0001
663
 
      */
664
 
      size_t pad_length= to_cs->mbminlen - from_offset;
665
 
      memset(to, 0, pad_length);
666
 
      memmove(to + pad_length, from, from_offset);
667
 
      nchars--;
668
 
      from+= from_offset;
669
 
      from_length-= from_offset;
670
 
      to+= to_cs->mbminlen;
671
 
      to_length-= to_cs->mbminlen;
672
 
    }
673
 
 
674
 
    set_if_smaller(from_length, to_length);
675
 
    res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
676
 
                                      nchars, &well_formed_error);
677
 
    memmove(to, from, res);
678
 
    *from_end_pos= from + res;
679
 
    *well_formed_error_pos= well_formed_error ? from + res : NULL;
680
 
    *cannot_convert_error_pos= NULL;
681
 
    if (from_offset)
682
 
      res+= to_cs->mbminlen;
683
 
  }
684
 
 
685
 
  return res;
 
904
    res= to - to_start;
 
905
  }
 
906
  return (uint32_t) res;
686
907
}
687
908
 
688
909
 
733
954
/* Factor the extern out */
734
955
extern const CHARSET_INFO *system_charset_info, *files_charset_info;
735
956
 
736
 
void String::append_identifier(const char *name, size_t in_length)
 
957
void String::append_identifier(const char *name, uint32_t in_length)
737
958
{
738
959
  const char *name_end;
739
960
  char quote_char;
788
1009
  std::swap(str_charset, s.str_charset);
789
1010
}
790
1011
 
791
 
void String::q_append(const size_t n)
792
 
{
793
 
  int8store(Ptr + str_length, n);
794
 
  str_length += 4;
795
 
}
796
 
void String::q_append(double d)
797
 
{
798
 
  float8store(Ptr + str_length, d);
799
 
  str_length += 8;
800
 
}
801
 
void String::q_append(double *d)
802
 
{
803
 
  float8store(Ptr + str_length, *d);
804
 
  str_length += 8;
805
 
}
806
 
void String::q_append(const char *data, size_t data_len)
807
 
{
808
 
  memcpy(Ptr + str_length, data, data_len);
809
 
  str_length += data_len;
810
 
}
811
 
 
812
 
void String::write_at_position(int position, size_t value)
813
 
{
814
 
  int8store(Ptr + position,value);
815
 
}
816
 
bool check_if_only_end_space(const CHARSET_INFO * const cs, char *str,
817
 
                             char *end)
818
 
{
819
 
  return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
820
 
}
821
 
 
822
 
} /* namespace drizzled */
823
 
 
824
 
bool operator==(const drizzled::String &s1, const drizzled::String &s2)
 
1012
 
 
1013
bool operator==(const String &s1, const String &s2)
825
1014
{
826
1015
  return stringcmp(&s1,&s2) == 0;
827
1016
}
828
1017
 
829
 
bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
 
1018
bool operator!=(const String &s1, const String &s2)
830
1019
{
831
1020
  return !(s1 == s2);
832
1021
}