~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_string.cc

  • Committer: Brian Aker
  • Date: 2008-12-15 19:32:58 UTC
  • mfrom: (677.1.2 devel)
  • Revision ID: brian@tangent.org-20081215193258-fsvc1sh9h7a9sb1t
Merge from Monty

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 ||
283
191
}
284
192
 
285
193
 
286
 
 
287
 
 
288
 
bool String::set_or_copy_aligned(const char *str,size_t arg_length,
 
194
/*
 
195
  Copy a multi-byte character sets with adding leading zeros.
 
196
 
 
197
  SYNOPSIS
 
198
 
 
199
  copy_aligned()
 
200
  str                   String to copy
 
201
  arg_length            Length of string. This should NOT be dividable with
 
202
                        cs->mbminlen.
 
203
  offset                arg_length % cs->mb_minlength
 
204
  cs                    Character set for 'str'
 
205
 
 
206
  NOTES
 
207
    For real multi-byte, ascii incompatible charactser sets,
 
208
    like UCS-2, add leading zeros if we have an incomplete character.
 
209
    Thus,
 
210
      SELECT _ucs2 0xAA
 
211
    will automatically be converted into
 
212
      SELECT _ucs2 0x00AA
 
213
 
 
214
  RETURN
 
215
    0  ok
 
216
    1  error
 
217
*/
 
218
 
 
219
bool String::copy_aligned(const char *str,uint32_t arg_length, uint32_t offset,
 
220
                          const CHARSET_INFO * const cs)
 
221
{
 
222
  /* How many bytes are in incomplete character */
 
223
  offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
 
224
  assert(offset && offset != cs->mbmaxlen);
 
225
 
 
226
  uint32_t aligned_length= arg_length + offset;
 
227
  if (alloc(aligned_length))
 
228
    return true;
 
229
 
 
230
  /*
 
231
    Note, this is only safe for big-endian UCS-2.
 
232
    If we add little-endian UCS-2 sometimes, this code
 
233
    will be more complicated. But it's OK for now.
 
234
  */
 
235
  memset(Ptr, 0, offset);
 
236
  memcpy(Ptr + offset, str, arg_length);
 
237
  Ptr[aligned_length]=0;
 
238
  /* str_length is always >= 0 as arg_length is != 0 */
 
239
  str_length= aligned_length;
 
240
  str_charset= cs;
 
241
  return false;
 
242
}
 
243
 
 
244
 
 
245
bool String::set_or_copy_aligned(const char *str,uint32_t arg_length,
289
246
                                 const CHARSET_INFO * const cs)
290
247
{
291
248
  /* How many bytes are in incomplete character */
292
 
  size_t offset= (arg_length % cs->mbminlen);
293
 
 
294
 
  assert(!offset); /* All characters are complete, just copy */
295
 
 
296
 
  set(str, arg_length, cs);
297
 
  return false;
 
249
  uint32_t offset= (arg_length % cs->mbminlen);
 
250
 
 
251
  if (!offset) /* All characters are complete, just copy */
 
252
  {
 
253
    set(str, arg_length, cs);
 
254
    return false;
 
255
  }
 
256
  return copy_aligned(str, arg_length, offset, cs);
298
257
}
299
258
 
300
259
        /* Copy with charset conversion */
301
260
 
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)
 
261
bool String::copy(const char *str, uint32_t arg_length,
 
262
                          const CHARSET_INFO * const from_cs,
 
263
                                  const CHARSET_INFO * const to_cs, uint32_t *errors)
305
264
{
306
 
  *errors= 0;
307
 
  return copy(str, arg_length, to_cs);
 
265
  uint32_t offset;
 
266
  if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
 
267
  {
 
268
    *errors= 0;
 
269
    return copy(str, arg_length, to_cs);
 
270
  }
 
271
  if ((from_cs == &my_charset_bin) && offset)
 
272
  {
 
273
    *errors= 0;
 
274
    return copy_aligned(str, arg_length, offset, to_cs);
 
275
  }
 
276
  uint32_t new_length= to_cs->mbmaxlen*arg_length;
 
277
  if (alloc(new_length))
 
278
    return true;
 
279
  str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
 
280
                              str, arg_length, from_cs, errors);
 
281
  str_charset=to_cs;
 
282
  return false;
308
283
}
309
284
 
310
285
 
327
302
 
328
303
*/
329
304
 
330
 
bool String::set_ascii(const char *str, size_t arg_length)
 
305
bool String::set_ascii(const char *str, uint32_t arg_length)
331
306
{
332
307
  if (str_charset->mbminlen == 1)
333
308
  {
334
309
    set(str, arg_length, str_charset);
335
310
    return 0;
336
311
  }
337
 
  size_t dummy_errors;
 
312
  uint32_t dummy_errors;
338
313
  return copy(str, arg_length, &my_charset_utf8_general_ci, str_charset, &dummy_errors);
339
314
}
340
315
 
 
316
 
 
317
/* This is used by mysql.cc */
 
318
 
 
319
bool String::fill(uint32_t max_length,char fill_char)
 
320
{
 
321
  if (str_length > max_length)
 
322
    Ptr[str_length=max_length]=0;
 
323
  else
 
324
  {
 
325
    if (realloc(max_length))
 
326
      return true;
 
327
    memset(Ptr+str_length, fill_char, max_length-str_length);
 
328
    str_length=max_length;
 
329
  }
 
330
  return false;
 
331
}
 
332
 
341
333
bool String::append(const String &s)
342
334
{
343
335
  if (s.length())
355
347
  Append an ASCII string to the a string of the current character set
356
348
*/
357
349
 
358
 
bool String::append(const char *s,size_t arg_length)
 
350
bool String::append(const char *s,uint32_t arg_length)
359
351
{
360
352
  if (!arg_length)
361
353
    return false;
362
354
 
363
355
  /*
 
356
    For an ASCII incompatible string, e.g. UCS-2, we need to convert
 
357
  */
 
358
  if (str_charset->mbminlen > 1)
 
359
  {
 
360
    uint32_t add_length=arg_length * str_charset->mbmaxlen;
 
361
    uint32_t dummy_errors;
 
362
    if (realloc(str_length+ add_length))
 
363
      return true;
 
364
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
365
                                  s, arg_length, &my_charset_utf8_general_ci,
 
366
                                  &dummy_errors);
 
367
    return false;
 
368
  }
 
369
 
 
370
  /*
364
371
    For an ASCII compatinble string we can just append.
365
372
  */
366
373
  if (realloc(str_length+arg_length))
386
393
  with character set recoding
387
394
*/
388
395
 
389
 
bool String::append(const char *s,size_t arg_length, const CHARSET_INFO * const)
390
 
{
391
 
  if (realloc(str_length + arg_length))
392
 
    return true;
393
 
  memcpy(Ptr + str_length, s, arg_length);
394
 
  str_length+= arg_length;
395
 
 
396
 
  return false;
397
 
}
398
 
 
399
 
 
400
 
bool String::append_with_prefill(const char *s,size_t arg_length,
401
 
                 size_t full_length, char fill_char)
 
396
bool String::append(const char *s,uint32_t arg_length, const CHARSET_INFO * const cs)
 
397
{
 
398
  uint32_t dummy_offset;
 
399
 
 
400
  if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
 
401
  {
 
402
    uint32_t add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
 
403
    uint32_t dummy_errors;
 
404
    if (realloc(str_length + add_length))
 
405
      return true;
 
406
    str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
 
407
                                  s, arg_length, cs, &dummy_errors);
 
408
  }
 
409
  else
 
410
  {
 
411
    if (realloc(str_length + arg_length))
 
412
      return true;
 
413
    memcpy(Ptr + str_length, s, arg_length);
 
414
    str_length+= arg_length;
 
415
  }
 
416
  return false;
 
417
}
 
418
 
 
419
 
 
420
bool String::append(IO_CACHE* file, uint32_t arg_length)
 
421
{
 
422
  if (realloc(str_length+arg_length))
 
423
    return true;
 
424
  if (my_b_read(file, (unsigned char*) Ptr + str_length, arg_length))
 
425
  {
 
426
    shrink(str_length);
 
427
    return true;
 
428
  }
 
429
  str_length+=arg_length;
 
430
  return false;
 
431
}
 
432
 
 
433
bool String::append_with_prefill(const char *s,uint32_t arg_length,
 
434
                 uint32_t full_length, char fill_char)
402
435
{
403
436
  int t_length= arg_length > full_length ? arg_length : full_length;
404
437
 
414
447
  return false;
415
448
}
416
449
 
417
 
size_t String::numchars()
 
450
uint32_t String::numchars()
418
451
{
419
452
  return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
420
453
}
421
454
 
422
 
int String::charpos(int i,size_t offset)
 
455
int String::charpos(int i,uint32_t offset)
423
456
{
424
457
  if (i <= 0)
425
458
    return i;
426
459
  return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
427
460
}
428
461
 
429
 
int String::strstr(const String &s,size_t offset)
 
462
int String::strstr(const String &s,uint32_t offset)
430
463
{
431
464
  if (s.length()+offset <= str_length)
432
465
  {
457
490
** Search string from end. Offset is offset to the end of string
458
491
*/
459
492
 
460
 
int String::strrstr(const String &s,size_t offset)
 
493
int String::strrstr(const String &s,uint32_t offset)
461
494
{
462
495
  if (s.length() <= offset && offset <= str_length)
463
496
  {
489
522
  If wrong parameter or not enough memory, do nothing
490
523
*/
491
524
 
492
 
bool String::replace(size_t offset,size_t arg_length,const String &to)
 
525
bool String::replace(uint32_t offset,uint32_t arg_length,const String &to)
493
526
{
494
527
  return replace(offset,arg_length,to.ptr(),to.length());
495
528
}
496
529
 
497
 
bool String::replace(size_t offset,size_t arg_length,
498
 
                     const char *to, size_t to_length)
 
530
bool String::replace(uint32_t offset,uint32_t arg_length,
 
531
                     const char *to, uint32_t to_length)
499
532
{
500
533
  long diff = (long) to_length-(long) arg_length;
501
534
  if (offset+arg_length <= str_length)
511
544
    {
512
545
      if (diff)
513
546
      {
514
 
        if (realloc(str_length+(size_t) diff))
 
547
        if (realloc(str_length+(uint32_t) diff))
515
548
          return true;
516
 
        internal::bmove_upp((unsigned char*) Ptr+str_length+diff,
517
 
                            (unsigned char*) Ptr+str_length,
518
 
                            str_length-offset-arg_length);
 
549
        bmove_upp((unsigned char*) Ptr+str_length+diff, (unsigned char*) Ptr+str_length,
 
550
                  str_length-offset-arg_length);
519
551
      }
520
552
      if (to_length)
521
553
        memcpy(Ptr+offset,to,to_length);
522
554
    }
523
 
    str_length+=(size_t) diff;
524
 
  }
525
 
  return false;
526
 
}
527
 
 
528
 
 
 
555
    str_length+=(uint32_t) diff;
 
556
  }
 
557
  return false;
 
558
}
 
559
 
 
560
 
 
561
// added by Holyfoot for "geometry" needs
 
562
int String::reserve(uint32_t space_needed, uint32_t grow_by)
 
563
{
 
564
  if (Alloced_length < str_length + space_needed)
 
565
  {
 
566
    if (realloc(Alloced_length + cmax(space_needed, grow_by) - 1))
 
567
      return true;
 
568
  }
 
569
  return false;
 
570
}
 
571
 
 
572
void String::qs_append(const char *str, uint32_t len)
 
573
{
 
574
  memcpy(Ptr + str_length, str, len + 1);
 
575
  str_length += len;
 
576
}
 
577
 
 
578
void String::qs_append(double d)
 
579
{
 
580
  char *buff = Ptr + str_length;
 
581
  str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff, NULL);
 
582
}
 
583
 
 
584
void String::qs_append(double *d)
 
585
{
 
586
  double ld;
 
587
  float8get(ld, (char*) d);
 
588
  qs_append(ld);
 
589
}
 
590
 
 
591
void String::qs_append(int i)
 
592
{
 
593
  char *buff= Ptr + str_length;
 
594
  char *end= int10_to_str(i, buff, -10);
 
595
  str_length+= (int) (end-buff);
 
596
}
 
597
 
 
598
void String::qs_append(uint32_t i)
 
599
{
 
600
  char *buff= Ptr + str_length;
 
601
  char *end= int10_to_str(i, buff, 10);
 
602
  str_length+= (int) (end-buff);
 
603
}
529
604
 
530
605
/*
531
606
  Compare strings according to collation, without end space.
574
649
 
575
650
int stringcmp(const String *s,const String *t)
576
651
{
577
 
  size_t s_len= s->length(), t_len= t->length(), len= min(s_len,t_len);
 
652
  uint32_t s_len=s->length(),t_len=t->length(),len=cmin(s_len,t_len);
578
653
  int cmp= memcmp(s->ptr(), t->ptr(), len);
579
654
  return (cmp) ? cmp : (int) (s_len - t_len);
580
655
}
581
656
 
582
657
 
583
 
String *copy_if_not_alloced(String *to,String *from,size_t from_length)
 
658
String *copy_if_not_alloced(String *to,String *from,uint32_t from_length)
584
659
{
585
660
  if (from->Alloced_length >= from_length)
586
661
    return from;
591
666
  }
592
667
  if (to->realloc(from_length))
593
668
    return from;                                // Actually an error
594
 
  if ((to->str_length= min(from->str_length,from_length)))
 
669
  if ((to->str_length=cmin(from->str_length,from_length)))
595
670
    memcpy(to->Ptr,from->Ptr,to->str_length);
596
671
  to->str_charset=from->str_charset;
597
672
  return to;
603
678
****************************************************************************/
604
679
 
605
680
/*
 
681
  copy a string from one character set to another
 
682
 
 
683
  SYNOPSIS
 
684
    copy_and_convert()
 
685
    to                  Store result here
 
686
    to_cs               Character set of result string
 
687
    from                Copy from here
 
688
    from_length         Length of from string
 
689
    from_cs             From character set
 
690
 
 
691
  NOTES
 
692
    'to' must be big enough as form_length * to_cs->mbmaxlen
 
693
 
 
694
  RETURN
 
695
    length of bytes copied to 'to'
 
696
*/
 
697
 
 
698
 
 
699
static uint32_t
 
700
copy_and_convert_extended(char *to, uint32_t to_length,
 
701
                          const CHARSET_INFO * const to_cs,
 
702
                          const char *from, uint32_t from_length,
 
703
                          const CHARSET_INFO * const from_cs,
 
704
                          uint32_t *errors)
 
705
{
 
706
  int         cnvres;
 
707
  my_wc_t     wc;
 
708
  const unsigned char *from_end= (const unsigned char*) from+from_length;
 
709
  char *to_start= to;
 
710
  unsigned char *to_end= (unsigned char*) to+to_length;
 
711
  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
712
  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
713
  uint32_t error_count= 0;
 
714
 
 
715
  while (1)
 
716
  {
 
717
    if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from,
 
718
                                      from_end)) > 0)
 
719
      from+= cnvres;
 
720
    else if (cnvres == MY_CS_ILSEQ)
 
721
    {
 
722
      error_count++;
 
723
      from++;
 
724
      wc= '?';
 
725
    }
 
726
    else if (cnvres > MY_CS_TOOSMALL)
 
727
    {
 
728
      /*
 
729
        A correct multibyte sequence detected
 
730
        But it doesn't have Unicode mapping.
 
731
      */
 
732
      error_count++;
 
733
      from+= (-cnvres);
 
734
      wc= '?';
 
735
    }
 
736
    else
 
737
      break;  // Not enough characters
 
738
 
 
739
outp:
 
740
    if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
741
      to+= cnvres;
 
742
    else if (cnvres == MY_CS_ILUNI && wc != '?')
 
743
    {
 
744
      error_count++;
 
745
      wc= '?';
 
746
      goto outp;
 
747
    }
 
748
    else
 
749
      break;
 
750
  }
 
751
  *errors= error_count;
 
752
  return (uint32_t) (to - to_start);
 
753
}
 
754
 
 
755
 
 
756
/*
 
757
  Optimized for quick copying of ASCII characters in the range 0x00..0x7F.
 
758
*/
 
759
uint32_t
 
760
copy_and_convert(char *to, uint32_t to_length, const CHARSET_INFO * const to_cs,
 
761
                 const char *from, uint32_t from_length,
 
762
                                 const CHARSET_INFO * const from_cs, uint32_t *errors)
 
763
{
 
764
  /*
 
765
    If any of the character sets is not ASCII compatible,
 
766
    immediately switch to slow mb_wc->wc_mb method.
 
767
  */
 
768
  if ((to_cs->state | from_cs->state) & MY_CS_NONASCII)
 
769
    return copy_and_convert_extended(to, to_length, to_cs,
 
770
                                     from, from_length, from_cs, errors);
 
771
 
 
772
  uint32_t length= cmin(to_length, from_length), length2= length;
 
773
 
 
774
#if defined(__i386__)
 
775
  /*
 
776
    Special loop for i386, it allows to refer to a
 
777
    non-aligned memory block as UINT32, which makes
 
778
    it possible to copy four bytes at once. This
 
779
    gives about 10% performance improvement comparing
 
780
    to byte-by-byte loop.
 
781
  */
 
782
  for ( ; length >= 4; length-= 4, from+= 4, to+= 4)
 
783
  {
 
784
    if ((*(uint32_t*)from) & 0x80808080)
 
785
      break;
 
786
    *((uint32_t*) to)= *((const uint32_t*) from);
 
787
  }
 
788
#endif
 
789
 
 
790
  for (; ; *to++= *from++, length--)
 
791
  {
 
792
    if (!length)
 
793
    {
 
794
      *errors= 0;
 
795
      return length2;
 
796
    }
 
797
    if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */
 
798
    {
 
799
      uint32_t copied_length= length2 - length;
 
800
      to_length-= copied_length;
 
801
      from_length-= copied_length;
 
802
      return copied_length + copy_and_convert_extended(to, to_length,
 
803
                                                       to_cs,
 
804
                                                       from, from_length,
 
805
                                                       from_cs,
 
806
                                                       errors);
 
807
    }
 
808
  }
 
809
 
 
810
  assert(false); // Should never get to here
 
811
  return 0;           // Make compiler happy
 
812
}
 
813
 
 
814
 
 
815
/**
 
816
  Copy string with HEX-encoding of "bad" characters.
 
817
 
 
818
  @details This functions copies the string pointed by "src"
 
819
  to the string pointed by "dst". Not more than "srclen" bytes
 
820
  are read from "src". Any sequences of bytes representing
 
821
  a not-well-formed substring (according to cs) are hex-encoded,
 
822
  and all well-formed substrings (according to cs) are copied as is.
 
823
  Not more than "dstlen" bytes are written to "dst". The number
 
824
  of bytes written to "dst" is returned.
 
825
 
 
826
   @param      cs       character set pointer of the destination string
 
827
   @param[out] dst      destination string
 
828
   @param      dstlen   size of dst
 
829
   @param      src      source string
 
830
   @param      srclen   length of src
 
831
 
 
832
   @retval     result length
 
833
*/
 
834
 
 
835
size_t
 
836
my_copy_with_hex_escaping(const CHARSET_INFO * const cs,
 
837
                          char *dst, size_t dstlen,
 
838
                          const char *src, size_t srclen)
 
839
{
 
840
  const char *srcend= src + srclen;
 
841
  char *dst0= dst;
 
842
 
 
843
  for ( ; src < srcend ; )
 
844
  {
 
845
    size_t chlen;
 
846
    if ((chlen= my_ismbchar(cs, src, srcend)))
 
847
    {
 
848
      if (dstlen < chlen)
 
849
        break; /* purecov: inspected */
 
850
      memcpy(dst, src, chlen);
 
851
      src+= chlen;
 
852
      dst+= chlen;
 
853
      dstlen-= chlen;
 
854
    }
 
855
    else if (*src & 0x80)
 
856
    {
 
857
      if (dstlen < 4)
 
858
        break; /* purecov: inspected */
 
859
      *dst++= '\\';
 
860
      *dst++= 'x';
 
861
      *dst++= _dig_vec_upper[((unsigned char) *src) >> 4];
 
862
      *dst++= _dig_vec_upper[((unsigned char) *src) & 15];
 
863
      src++;
 
864
      dstlen-= 4;
 
865
    }
 
866
    else
 
867
    {
 
868
      if (dstlen < 1)
 
869
        break; /* purecov: inspected */
 
870
      *dst++= *src++;
 
871
      dstlen--;
 
872
    }
 
873
  }
 
874
  return dst - dst0;
 
875
}
 
876
 
 
877
/*
606
878
  copy a string,
607
879
  with optional character set conversion,
608
880
  with optional left padding (for binary -> UCS2 conversion)
629
901
*/
630
902
 
631
903
 
632
 
size_t
 
904
uint32_t
633
905
well_formed_copy_nchars(const CHARSET_INFO * const to_cs,
634
 
                        char *to, size_t to_length,
 
906
                        char *to, uint32_t to_length,
635
907
                        const CHARSET_INFO * const from_cs,
636
 
                        const char *from, size_t from_length,
637
 
                        size_t nchars,
 
908
                        const char *from, uint32_t from_length,
 
909
                        uint32_t nchars,
638
910
                        const char **well_formed_error_pos,
639
911
                        const char **cannot_convert_error_pos,
640
912
                        const char **from_end_pos)
641
913
{
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
 
  {
 
914
  uint32_t res;
 
915
 
 
916
  if ((to_cs == &my_charset_bin) ||
 
917
      (from_cs == &my_charset_bin) ||
 
918
      (to_cs == from_cs) ||
 
919
      my_charset_same(from_cs, to_cs))
 
920
  {
 
921
    if (to_length < to_cs->mbminlen || !nchars)
 
922
    {
 
923
      *from_end_pos= from;
 
924
      *cannot_convert_error_pos= NULL;
 
925
      *well_formed_error_pos= NULL;
 
926
      return 0;
 
927
    }
 
928
 
 
929
    if (to_cs == &my_charset_bin)
 
930
    {
 
931
      res= cmin(cmin(nchars, to_length), from_length);
 
932
      memmove(to, from, res);
 
933
      *from_end_pos= from + res;
 
934
      *well_formed_error_pos= NULL;
 
935
      *cannot_convert_error_pos= NULL;
 
936
    }
 
937
    else
 
938
    {
 
939
      int well_formed_error;
 
940
      uint32_t from_offset;
 
941
 
 
942
      if ((from_offset= (from_length % to_cs->mbminlen)) &&
 
943
          (from_cs == &my_charset_bin))
 
944
      {
 
945
        /*
 
946
          Copying from BINARY to UCS2 needs to prepend zeros sometimes:
 
947
          INSERT INTO t1 (ucs2_column) VALUES (0x01);
 
948
          0x01 -> 0x0001
 
949
        */
 
950
        uint32_t pad_length= to_cs->mbminlen - from_offset;
 
951
        memset(to, 0, pad_length);
 
952
        memmove(to + pad_length, from, from_offset);
 
953
        nchars--;
 
954
        from+= from_offset;
 
955
        from_length-= from_offset;
 
956
        to+= to_cs->mbminlen;
 
957
        to_length-= to_cs->mbminlen;
 
958
      }
 
959
 
 
960
      set_if_smaller(from_length, to_length);
 
961
      res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
 
962
                                        nchars, &well_formed_error);
 
963
      memmove(to, from, res);
 
964
      *from_end_pos= from + res;
 
965
      *well_formed_error_pos= well_formed_error ? from + res : NULL;
 
966
      *cannot_convert_error_pos= NULL;
 
967
      if (from_offset)
 
968
        res+= to_cs->mbminlen;
 
969
    }
 
970
  }
 
971
  else
 
972
  {
 
973
    int cnvres;
 
974
    my_wc_t wc;
 
975
    my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
976
    my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
977
    const unsigned char *from_end= (const unsigned char*) from + from_length;
 
978
    unsigned char *to_end= (unsigned char*) to + to_length;
 
979
    char *to_start= to;
 
980
    *well_formed_error_pos= NULL;
 
981
    *cannot_convert_error_pos= NULL;
 
982
 
 
983
    for ( ; nchars; nchars--)
 
984
    {
 
985
      const char *from_prev= from;
 
986
      if ((cnvres= (*mb_wc)(from_cs, &wc, (unsigned char*) from, from_end)) > 0)
 
987
        from+= cnvres;
 
988
      else if (cnvres == MY_CS_ILSEQ)
 
989
      {
 
990
        if (!*well_formed_error_pos)
 
991
          *well_formed_error_pos= from;
 
992
        from++;
 
993
        wc= '?';
 
994
      }
 
995
      else if (cnvres > MY_CS_TOOSMALL)
 
996
      {
 
997
        /*
 
998
          A correct multibyte sequence detected
 
999
          But it doesn't have Unicode mapping.
 
1000
        */
 
1001
        if (!*cannot_convert_error_pos)
 
1002
          *cannot_convert_error_pos= from;
 
1003
        from+= (-cnvres);
 
1004
        wc= '?';
 
1005
      }
 
1006
      else
 
1007
        break;  // Not enough characters
 
1008
 
 
1009
outp:
 
1010
      if ((cnvres= (*wc_mb)(to_cs, wc, (unsigned char*) to, to_end)) > 0)
 
1011
        to+= cnvres;
 
1012
      else if (cnvres == MY_CS_ILUNI && wc != '?')
 
1013
      {
 
1014
        if (!*cannot_convert_error_pos)
 
1015
          *cannot_convert_error_pos= from_prev;
 
1016
        wc= '?';
 
1017
        goto outp;
 
1018
      }
 
1019
      else
 
1020
      {
 
1021
        from= from_prev;
 
1022
        break;
 
1023
      }
 
1024
    }
651
1025
    *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;
 
1026
    res= to - to_start;
 
1027
  }
 
1028
  return (uint32_t) res;
700
1029
}
701
1030
 
702
1031
 
734
1063
  }
735
1064
}
736
1065
 
737
 
/*
738
 
  Quote the given identifier.
739
 
  If the given identifier is empty, it will be quoted.
740
 
 
741
 
  SYNOPSIS
742
 
  append_identifier()
743
 
  name                  the identifier to be appended
744
 
  name_length           length of the appending identifier
745
 
*/
746
 
 
747
 
/* Factor the extern out */
748
 
extern const CHARSET_INFO *system_charset_info, *files_charset_info;
749
 
 
750
 
void String::append_identifier(const char *name, size_t in_length)
751
 
{
752
 
  const char *name_end;
753
 
  char quote_char;
754
 
  int q= '`';
755
 
 
756
 
  /*
757
 
    The identifier must be quoted as it includes a quote character or
758
 
   it's a keyword
759
 
  */
760
 
 
761
 
  reserve(in_length*2 + 2);
762
 
  quote_char= (char) q;
763
 
  append(&quote_char, 1, system_charset_info);
764
 
 
765
 
  for (name_end= name+in_length ; name < name_end ; name+= in_length)
766
 
  {
767
 
    unsigned char chr= (unsigned char) *name;
768
 
    in_length= my_mbcharlen(system_charset_info, chr);
769
 
    /*
770
 
      my_mbcharlen can return 0 on a wrong multibyte
771
 
      sequence. It is possible when upgrading from 4.0,
772
 
      and identifier contains some accented characters.
773
 
      The manual says it does not work. So we'll just
774
 
      change length to 1 not to hang in the endless loop.
775
 
    */
776
 
    if (!in_length)
777
 
      in_length= 1;
778
 
    if (in_length == 1 && chr == (unsigned char) quote_char)
779
 
      append(&quote_char, 1, system_charset_info);
780
 
    append(name, in_length, system_charset_info);
781
 
  }
782
 
  append(&quote_char, 1, system_charset_info);
783
 
}
784
 
 
785
1066
 
786
1067
/*
787
1068
  Exchange state of this object and argument.
802
1083
  std::swap(str_charset, s.str_charset);
803
1084
}
804
1085
 
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)
 
1086
 
 
1087
bool operator==(const String &s1, const String &s2)
850
1088
{
851
1089
  return stringcmp(&s1,&s2) == 0;
852
1090
}
853
1091
 
854
 
bool operator!=(const drizzled::String &s1, const drizzled::String &s2)
 
1092
bool operator!=(const String &s1, const String &s2)
855
1093
{
856
1094
  return !(s1 == s2);
857
1095
}