1#ifndef SQL_STRING_INCLUDED
2#define SQL_STRING_INCLUDED
3
4/*
5 Copyright (c) 2000, 2013, Oracle and/or its affiliates.
6 Copyright (c) 2008, 2018, MariaDB Corporation.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; version 2 of the License.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
20
21/* This file is originally from the mysql distribution. Coded by monty */
22
23#ifdef USE_PRAGMA_INTERFACE
24#pragma interface /* gcc class implementation */
25#endif
26
27#include "m_ctype.h" /* my_charset_bin */
28#include <my_sys.h> /* alloc_root, my_free, my_realloc */
29#include "m_string.h" /* TRASH */
30
31class String;
32typedef struct st_io_cache IO_CACHE;
33typedef struct st_mem_root MEM_ROOT;
34
35#include "pack.h"
36int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
37String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
38inline uint32 copy_and_convert(char *to, size_t to_length,
39 CHARSET_INFO *to_cs,
40 const char *from, size_t from_length,
41 CHARSET_INFO *from_cs, uint *errors)
42{
43 return my_convert(to, (uint)to_length, to_cs, from, (uint)from_length, from_cs, errors);
44}
45
46
47class String_copy_status: protected MY_STRCOPY_STATUS
48{
49public:
50 const char *source_end_pos() const
51 { return m_source_end_pos; }
52 const char *well_formed_error_pos() const
53 { return m_well_formed_error_pos; }
54};
55
56
57class Well_formed_prefix_status: public String_copy_status
58{
59public:
60 Well_formed_prefix_status(CHARSET_INFO *cs,
61 const char *str, const char *end, size_t nchars)
62 { cs->cset->well_formed_char_length(cs, str, end, nchars, this); }
63};
64
65
66class Well_formed_prefix: public Well_formed_prefix_status
67{
68 const char *m_str; // The beginning of the string
69public:
70 Well_formed_prefix(CHARSET_INFO *cs, const char *str, const char *end,
71 size_t nchars)
72 :Well_formed_prefix_status(cs, str, end, nchars), m_str(str)
73 { }
74 Well_formed_prefix(CHARSET_INFO *cs, const char *str, size_t length,
75 size_t nchars)
76 :Well_formed_prefix_status(cs, str, str + length, nchars), m_str(str)
77 { }
78 Well_formed_prefix(CHARSET_INFO *cs, const char *str, size_t length)
79 :Well_formed_prefix_status(cs, str, str + length, length), m_str(str)
80 { }
81 size_t length() const { return m_source_end_pos - m_str; }
82};
83
84
85class String_copier: public String_copy_status,
86 protected MY_STRCONV_STATUS
87{
88public:
89 const char *cannot_convert_error_pos() const
90 { return m_cannot_convert_error_pos; }
91 const char *most_important_error_pos() const
92 {
93 return well_formed_error_pos() ? well_formed_error_pos() :
94 cannot_convert_error_pos();
95 }
96 /*
97 Convert a string between character sets.
98 "dstcs" and "srccs" cannot be &my_charset_bin.
99 */
100 size_t convert_fix(CHARSET_INFO *dstcs, char *dst, size_t dst_length,
101 CHARSET_INFO *srccs, const char *src, size_t src_length, size_t nchars)
102 {
103 return my_convert_fix(dstcs, dst, dst_length,
104 srccs, src, src_length, nchars, this, this);
105 }
106 /*
107 Copy a string. Fix bad bytes/characters to '?'.
108 */
109 uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length,
110 CHARSET_INFO *from_cs, const char *from, size_t from_length, size_t nchars);
111 // Same as above, but without the "nchars" limit.
112 uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length,
113 CHARSET_INFO *from_cs, const char *from, size_t from_length)
114 {
115 return well_formed_copy(to_cs, to, to_length,
116 from_cs, from, from_length,
117 from_length /* No limit on "nchars"*/);
118 }
119};
120
121
122size_t my_copy_with_hex_escaping(CHARSET_INFO *cs,
123 char *dst, size_t dstlen,
124 const char *src, size_t srclen);
125uint convert_to_printable(char *to, size_t to_len,
126 const char *from, size_t from_len,
127 CHARSET_INFO *from_cs, size_t nbytes= 0);
128
129class String
130{
131 char *Ptr;
132 uint32 str_length,Alloced_length, extra_alloc;
133 bool alloced,thread_specific;
134 CHARSET_INFO *str_charset;
135public:
136 String()
137 {
138 Ptr=0; str_length=Alloced_length=extra_alloc=0;
139 alloced= thread_specific= 0;
140 str_charset= &my_charset_bin;
141 }
142 String(size_t length_arg)
143 {
144 alloced= thread_specific= 0;
145 Alloced_length= extra_alloc= 0; (void) real_alloc(length_arg);
146 str_charset= &my_charset_bin;
147 }
148 String(const char *str, CHARSET_INFO *cs)
149 {
150 Ptr=(char*) str; str_length= (uint32) strlen(str);
151 Alloced_length= extra_alloc= 0;
152 alloced= thread_specific= 0;
153 str_charset=cs;
154 }
155 /*
156 NOTE: If one intend to use the c_ptr() method, the following two
157 contructors need the size of memory for STR to be at least LEN+1 (to make
158 room for zero termination).
159 */
160 String(const char *str,size_t len, CHARSET_INFO *cs)
161 {
162 Ptr=(char*) str; str_length=(uint32)len; Alloced_length= extra_alloc=0;
163 alloced= thread_specific= 0;
164 str_charset=cs;
165 }
166 String(char *str,size_t len, CHARSET_INFO *cs)
167 {
168 Ptr=(char*) str; Alloced_length=str_length=(uint32)len; extra_alloc= 0;
169 alloced= thread_specific= 0;
170 str_charset=cs;
171 }
172 String(const String &str)
173 {
174 Ptr=str.Ptr ; str_length=str.str_length ;
175 Alloced_length=str.Alloced_length; extra_alloc= 0;
176 alloced= thread_specific= 0;
177 str_charset=str.str_charset;
178 }
179 static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
180 { return (void*) alloc_root(mem_root, size); }
181 static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
182 { return alloc_root(mem_root, size); }
183 static void operator delete(void *ptr_arg, size_t size)
184 {
185 (void) ptr_arg;
186 (void) size;
187 TRASH_FREE(ptr_arg, size);
188 }
189 static void operator delete(void *, MEM_ROOT *)
190 { /* never called */ }
191 static void operator delete[](void *ptr, size_t size)
192 { TRASH_FREE(ptr, size); }
193 static void operator delete[](void *, MEM_ROOT *)
194 { /* never called */ }
195
196 ~String() { free(); }
197
198 /* Mark variable thread specific it it's not allocated already */
199 inline void set_thread_specific()
200 {
201 if (!alloced)
202 thread_specific= 1;
203 }
204 inline void set_charset(CHARSET_INFO *charset_arg)
205 { str_charset= charset_arg; }
206 inline CHARSET_INFO *charset() const { return str_charset; }
207 inline uint32 length() const { return str_length;}
208 inline uint32 alloced_length() const { return Alloced_length;}
209 inline uint32 extra_allocation() const { return extra_alloc;}
210 inline char& operator [] (size_t i) const { return Ptr[i]; }
211 inline void length(size_t len) { str_length=(uint32)len ; }
212 inline void extra_allocation(size_t len) { extra_alloc= (uint32)len; }
213 inline bool is_empty() const { return (str_length == 0); }
214 inline void mark_as_const() { Alloced_length= 0;}
215 inline const char *ptr() const { return Ptr; }
216 inline const char *end() const { return Ptr + str_length; }
217 inline char *c_ptr()
218 {
219 DBUG_ASSERT(!alloced || !Ptr || !Alloced_length ||
220 (Alloced_length >= (str_length + 1)));
221
222 if (!Ptr || Ptr[str_length]) /* Should be safe */
223 (void) realloc(str_length);
224 return Ptr;
225 }
226 inline char *c_ptr_quick()
227 {
228 if (Ptr && str_length < Alloced_length)
229 Ptr[str_length]=0;
230 return Ptr;
231 }
232 inline char *c_ptr_safe()
233 {
234 if (Ptr && str_length < Alloced_length)
235 Ptr[str_length]=0;
236 else
237 (void) realloc(str_length);
238 return Ptr;
239 }
240 LEX_STRING lex_string() const
241 {
242 LEX_STRING str = { (char*) ptr(), length() };
243 return str;
244 }
245 LEX_CSTRING lex_cstring() const
246 {
247 LEX_CSTRING skr = { ptr(), length() };
248 return skr;
249 }
250
251 void set(String &str,size_t offset,size_t arg_length)
252 {
253 DBUG_ASSERT(&str != this);
254 free();
255 Ptr=(char*) str.ptr()+offset; str_length=(uint32)arg_length;
256 if (str.Alloced_length)
257 Alloced_length=(uint32)(str.Alloced_length-offset);
258 str_charset=str.str_charset;
259 }
260
261
262 /**
263 Points the internal buffer to the supplied one. The old buffer is freed.
264 @param str Pointer to the new buffer.
265 @param arg_length Length of the new buffer in characters, excluding any
266 null character.
267 @param cs Character set to use for interpreting string data.
268 @note The new buffer will not be null terminated.
269 */
270 inline void set(char *str,size_t arg_length, CHARSET_INFO *cs)
271 {
272 free();
273 Ptr=(char*) str; str_length=Alloced_length=(uint32)arg_length;
274 str_charset=cs;
275 }
276 inline void set(const char *str,size_t arg_length, CHARSET_INFO *cs)
277 {
278 free();
279 Ptr=(char*) str; str_length=(uint32)arg_length;
280 str_charset=cs;
281 }
282 bool set_ascii(const char *str, size_t arg_length);
283 inline void set_quick(char *str,size_t arg_length, CHARSET_INFO *cs)
284 {
285 if (!alloced)
286 {
287 Ptr=(char*) str; str_length=Alloced_length=(uint32)arg_length;
288 }
289 str_charset=cs;
290 }
291 bool set_int(longlong num, bool unsigned_flag, CHARSET_INFO *cs);
292 bool set(int num, CHARSET_INFO *cs) { return set_int(num, false, cs); }
293 bool set(uint num, CHARSET_INFO *cs) { return set_int(num, true, cs); }
294 bool set(long num, CHARSET_INFO *cs) { return set_int(num, false, cs); }
295 bool set(ulong num, CHARSET_INFO *cs) { return set_int(num, true, cs); }
296 bool set(longlong num, CHARSET_INFO *cs) { return set_int(num, false, cs); }
297 bool set(ulonglong num, CHARSET_INFO *cs) { return set_int((longlong)num, true, cs); }
298 bool set_real(double num,uint decimals, CHARSET_INFO *cs);
299
300 bool set_hex(ulonglong num);
301 bool set_hex(const char *str, uint32 len);
302
303 /* Take over handling of buffer from some other object */
304 void reset(char *ptr_arg, size_t length_arg, size_t alloced_length_arg,
305 CHARSET_INFO *cs)
306 {
307 free();
308 Ptr= ptr_arg;
309 str_length= (uint32)length_arg;
310 Alloced_length= (uint32)alloced_length_arg;
311 str_charset= cs;
312 alloced= ptr_arg != 0;
313 }
314
315 /* Forget about the buffer, let some other object handle it */
316 char *release()
317 {
318 char *old= Ptr;
319 Ptr=0; str_length= Alloced_length= extra_alloc= 0;
320 alloced= thread_specific= 0;
321 return old;
322 }
323
324 /*
325 PMG 2004.11.12
326 This is a method that works the same as perl's "chop". It simply
327 drops the last character of a string. This is useful in the case
328 of the federated storage handler where I'm building a unknown
329 number, list of values and fields to be used in a sql insert
330 statement to be run on the remote server, and have a comma after each.
331 When the list is complete, I "chop" off the trailing comma
332
333 ex.
334 String stringobj;
335 stringobj.append("VALUES ('foo', 'fi', 'fo',");
336 stringobj.chop();
337 stringobj.append(")");
338
339 In this case, the value of string was:
340
341 VALUES ('foo', 'fi', 'fo',
342 VALUES ('foo', 'fi', 'fo'
343 VALUES ('foo', 'fi', 'fo')
344
345 */
346 inline void chop()
347 {
348 str_length--;
349 Ptr[str_length]= '\0';
350 DBUG_ASSERT(strlen(Ptr) == str_length);
351 }
352
353 inline void free()
354 {
355 if (alloced)
356 {
357 alloced=0;
358 my_free(Ptr);
359 }
360 Alloced_length= extra_alloc= 0;
361 Ptr=0;
362 str_length=0; /* Safety */
363 }
364 inline bool alloc(size_t arg_length)
365 {
366 if (arg_length < Alloced_length)
367 return 0;
368 return real_alloc(arg_length);
369 }
370 bool real_alloc(size_t arg_length); // Empties old string
371 bool realloc_raw(size_t arg_length);
372 bool realloc(size_t arg_length)
373 {
374 if (realloc_raw(arg_length))
375 return TRUE;
376 Ptr[arg_length]=0; // This make other funcs shorter
377 return FALSE;
378 }
379 bool realloc_with_extra(size_t arg_length)
380 {
381 if (extra_alloc < 4096)
382 extra_alloc= extra_alloc*2+128;
383 if (realloc_raw(arg_length + extra_alloc))
384 return TRUE;
385 Ptr[arg_length]=0; // This make other funcs shorter
386 return FALSE;
387 }
388 bool realloc_with_extra_if_needed(size_t arg_length)
389 {
390 if (arg_length < Alloced_length)
391 {
392 Ptr[arg_length]=0; // behave as if realloc was called.
393 return 0;
394 }
395 return realloc_with_extra(arg_length);
396 }
397 // Shrink the buffer, but only if it is allocated on the heap.
398 inline void shrink(size_t arg_length)
399 {
400 if (!is_alloced())
401 return;
402 if (ALIGN_SIZE(arg_length+1) < Alloced_length)
403 {
404 char *new_ptr;
405 if (unlikely(!(new_ptr=(char*)
406 my_realloc(Ptr,
407 arg_length,MYF((thread_specific ?
408 MY_THREAD_SPECIFIC : 0))))))
409 {
410 Alloced_length = 0;
411 real_alloc(arg_length);
412 }
413 else
414 {
415 Ptr=new_ptr;
416 Alloced_length=(uint32)arg_length;
417 }
418 }
419 }
420 bool is_alloced() const { return alloced; }
421 inline String& operator = (const String &s)
422 {
423 if (&s != this)
424 {
425 /*
426 It is forbidden to do assignments like
427 some_string = substring_of_that_string
428 */
429 DBUG_ASSERT(!s.uses_buffer_owned_by(this));
430 free();
431 Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
432 str_charset=s.str_charset;
433 }
434 return *this;
435 }
436
437 bool copy(); // Alloc string if not alloced
438 bool copy(const String &s); // Allocate new string
439 bool copy(const char *s,size_t arg_length, CHARSET_INFO *cs); // Allocate new string
440 static bool needs_conversion(size_t arg_length,
441 CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
442 uint32 *offset);
443 static bool needs_conversion_on_storage(size_t arg_length,
444 CHARSET_INFO *cs_from,
445 CHARSET_INFO *cs_to);
446 bool copy_aligned(const char *s, size_t arg_length, size_t offset,
447 CHARSET_INFO *cs);
448 bool set_or_copy_aligned(const char *s, size_t arg_length, CHARSET_INFO *cs);
449 bool copy(const char*s, size_t arg_length, CHARSET_INFO *csfrom,
450 CHARSET_INFO *csto, uint *errors);
451 bool copy(const String *str, CHARSET_INFO *tocs, uint *errors)
452 {
453 return copy(str->ptr(), str->length(), str->charset(), tocs, errors);
454 }
455 bool copy(CHARSET_INFO *tocs,
456 CHARSET_INFO *fromcs, const char *src, size_t src_length,
457 size_t nchars, String_copier *copier)
458 {
459 if (unlikely(alloc(tocs->mbmaxlen * src_length)))
460 return true;
461 str_length= copier->well_formed_copy(tocs, Ptr, Alloced_length,
462 fromcs, src, (uint)src_length, (uint)nchars);
463 str_charset= tocs;
464 return false;
465 }
466 void move(String &s)
467 {
468 free();
469 Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
470 extra_alloc= s.extra_alloc;
471 alloced= s.alloced;
472 thread_specific= s.thread_specific;
473 s.alloced= 0;
474 }
475 bool append(const String &s);
476 bool append(const char *s);
477 bool append(const LEX_STRING *ls)
478 {
479 DBUG_ASSERT(ls->length < UINT_MAX32 &&
480 ((ls->length == 0 && !ls->str) ||
481 ls->length == strlen(ls->str)));
482 return append(ls->str, (uint32) ls->length);
483 }
484 bool append(const LEX_CSTRING *ls)
485 {
486 DBUG_ASSERT(ls->length < UINT_MAX32 &&
487 ((ls->length == 0 && !ls->str) ||
488 ls->length == strlen(ls->str)));
489 return append(ls->str, (uint32) ls->length);
490 }
491 bool append(const LEX_CSTRING &ls)
492 {
493 return append(&ls);
494 }
495 bool append(const char *s, size_t size);
496 bool append(const char *s, size_t arg_length, CHARSET_INFO *cs);
497 bool append_ulonglong(ulonglong val);
498 bool append_longlong(longlong val);
499 bool append(IO_CACHE* file, uint32 arg_length);
500 bool append_with_prefill(const char *s, uint32 arg_length,
501 uint32 full_length, char fill_char);
502 bool append_parenthesized(long nr, int radix= 10);
503 int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
504 int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
505 bool replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
506 bool replace(uint32 offset,uint32 arg_length,const String &to);
507 inline bool append(char chr)
508 {
509 if (str_length < Alloced_length)
510 {
511 Ptr[str_length++]=chr;
512 }
513 else
514 {
515 if (unlikely(realloc_with_extra(str_length + 1)))
516 return 1;
517 Ptr[str_length++]=chr;
518 }
519 return 0;
520 }
521 bool append_hex(const char *src, uint32 srclen)
522 {
523 for (const char *src_end= src + srclen ; src != src_end ; src++)
524 {
525 if (unlikely(append(_dig_vec_lower[((uchar) *src) >> 4])) ||
526 unlikely(append(_dig_vec_lower[((uchar) *src) & 0x0F])))
527 return true;
528 }
529 return false;
530 }
531 bool append_hex(const uchar *src, uint32 srclen)
532 {
533 return append_hex((const char*)src, srclen);
534 }
535 bool fill(uint32 max_length,char fill);
536 void strip_sp();
537 friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
538 friend int stringcmp(const String *a,const String *b);
539 friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
540 friend class Field;
541 uint32 numchars() const;
542 int charpos(longlong i,uint32 offset=0);
543
544 int reserve(size_t space_needed)
545 {
546 return realloc(str_length + space_needed);
547 }
548 int reserve(size_t space_needed, size_t grow_by);
549
550 /*
551 The following append operations do NOT check alloced memory
552 q_*** methods writes values of parameters itself
553 qs_*** methods writes string representation of value
554 */
555 void q_append(const char c)
556 {
557 Ptr[str_length++] = c;
558 }
559 void q_append2b(const uint32 n)
560 {
561 int2store(Ptr + str_length, n);
562 str_length += 2;
563 }
564 void q_append(const uint32 n)
565 {
566 int4store(Ptr + str_length, n);
567 str_length += 4;
568 }
569 void q_append(double d)
570 {
571 float8store(Ptr + str_length, d);
572 str_length += 8;
573 }
574 void q_append(double *d)
575 {
576 float8store(Ptr + str_length, *d);
577 str_length += 8;
578 }
579 void q_append(const char *data, size_t data_len)
580 {
581 memcpy(Ptr + str_length, data, data_len);
582 DBUG_ASSERT(str_length <= UINT_MAX32 - data_len);
583 str_length += (uint)data_len;
584 }
585 void q_append(const LEX_CSTRING *ls)
586 {
587 DBUG_ASSERT(ls->length < UINT_MAX32 &&
588 ((ls->length == 0 && !ls->str) ||
589 ls->length == strlen(ls->str)));
590 q_append(ls->str, (uint32) ls->length);
591 }
592
593 void write_at_position(int position, uint32 value)
594 {
595 int4store(Ptr + position,value);
596 }
597
598 void qs_append(const char *str)
599 {
600 qs_append(str, (uint32)strlen(str));
601 }
602 void qs_append(const LEX_CSTRING *ls)
603 {
604 DBUG_ASSERT(ls->length < UINT_MAX32 &&
605 ((ls->length == 0 && !ls->str) ||
606 ls->length == strlen(ls->str)));
607 qs_append(ls->str, (uint32)ls->length);
608 }
609 void qs_append(const char *str, size_t len);
610 void qs_append_hex(const char *str, uint32 len);
611 void qs_append(double d);
612 void qs_append(double *d);
613 inline void qs_append(const char c)
614 {
615 Ptr[str_length]= c;
616 str_length++;
617 }
618 void qs_append(int i);
619 void qs_append(uint i)
620 {
621 qs_append((ulonglong)i);
622 }
623 void qs_append(ulong i)
624 {
625 qs_append((ulonglong)i);
626 }
627 void qs_append(ulonglong i);
628 void qs_append(longlong i, int radix)
629 {
630 char *buff= Ptr + str_length;
631 char *end= ll2str(i, buff, radix, 0);
632 str_length+= uint32(end-buff);
633 }
634
635 /* Inline (general) functions used by the protocol functions */
636
637 inline char *prep_append(uint32 arg_length, uint32 step_alloc)
638 {
639 uint32 new_length= arg_length + str_length;
640 if (new_length > Alloced_length)
641 {
642 if (unlikely(realloc(new_length + step_alloc)))
643 return 0;
644 }
645 uint32 old_length= str_length;
646 str_length+= arg_length;
647 return Ptr+ old_length; /* Area to use */
648 }
649
650
651 inline bool append(const char *s, uint32 arg_length, uint32 step_alloc)
652 {
653 uint32 new_length= arg_length + str_length;
654 if (new_length > Alloced_length &&
655 unlikely(realloc(new_length + step_alloc)))
656 return TRUE;
657 memcpy(Ptr+str_length, s, arg_length);
658 str_length+= arg_length;
659 return FALSE;
660 }
661 void print(String *to) const;
662 void print_with_conversion(String *to, CHARSET_INFO *cs) const;
663 void print(String *to, CHARSET_INFO *cs) const
664 {
665 if (my_charset_same(charset(), cs))
666 print(to);
667 else
668 print_with_conversion(to, cs);
669 }
670
671 bool append_for_single_quote(const char *st, size_t len);
672 bool append_for_single_quote(const String *s)
673 {
674 return append_for_single_quote(s->ptr(), s->length());
675 }
676 bool append_for_single_quote(const char *st)
677 {
678 size_t len= strlen(st);
679 DBUG_ASSERT(len < UINT_MAX32);
680 return append_for_single_quote(st, (uint32) len);
681 }
682
683 /* Swap two string objects. Efficient way to exchange data without memcpy. */
684 void swap(String &s);
685
686 inline bool uses_buffer_owned_by(const String *s) const
687 {
688 return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
689 }
690 uint well_formed_length() const
691 {
692 return (uint) Well_formed_prefix(charset(), ptr(), length()).length();
693 }
694 bool is_ascii() const
695 {
696 if (length() == 0)
697 return TRUE;
698 if (charset()->mbminlen > 1)
699 return FALSE;
700 for (const char *c= ptr(), *c_end= c + length(); c < c_end; c++)
701 {
702 if (!my_isascii(*c))
703 return FALSE;
704 }
705 return TRUE;
706 }
707 bool bin_eq(const String *other) const
708 {
709 return length() == other->length() &&
710 !memcmp(ptr(), other->ptr(), length());
711 }
712 bool eq(const String *other, CHARSET_INFO *cs) const
713 {
714 return !sortcmp(this, other, cs);
715 }
716 void q_net_store_length(ulonglong length)
717 {
718 DBUG_ASSERT(Alloced_length >= (str_length + net_length_size(length)));
719 char *pos= (char *) net_store_length((uchar *)(Ptr + str_length), length);
720 str_length= uint32(pos - Ptr);
721 }
722 void q_net_store_data(const uchar *from, size_t length)
723 {
724 DBUG_ASSERT(length < UINT_MAX32);
725 DBUG_ASSERT(Alloced_length >= (str_length + length +
726 net_length_size(length)));
727 q_net_store_length(length);
728 q_append((const char *)from, (uint32) length);
729 }
730};
731
732
733// The following class is a backport from MySQL 5.6:
734/**
735 String class wrapper with a preallocated buffer of size buff_sz
736
737 This class allows to replace sequences of:
738 char buff[12345];
739 String str(buff, sizeof(buff));
740 str.length(0);
741 with a simple equivalent declaration:
742 StringBuffer<12345> str;
743*/
744
745template<size_t buff_sz>
746class StringBuffer : public String
747{
748 char buff[buff_sz];
749
750public:
751 StringBuffer() : String(buff, buff_sz, &my_charset_bin) { length(0); }
752 explicit StringBuffer(CHARSET_INFO *cs) : String(buff, buff_sz, cs)
753 {
754 length(0);
755 }
756 StringBuffer(const char *str, size_t length_arg, CHARSET_INFO *cs)
757 : String(buff, buff_sz, cs)
758 {
759 set(str, length_arg, cs);
760 }
761};
762
763
764static inline bool check_if_only_end_space(CHARSET_INFO *cs,
765 const char *str,
766 const char *end)
767{
768 return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
769}
770
771int append_query_string(CHARSET_INFO *csinfo, String *to,
772 const char *str, size_t len, bool no_backslash);
773
774#endif /* SQL_STRING_INCLUDED */
775