45
54
cs < all_charsets+array_elements(all_charsets)-1 ;
48
if ( cs[0] && cs[0]->name &&
49
!my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
57
if ( cs[0] && cs[0]->name &&
58
!my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
50
59
return cs[0]->number;
56
65
static bool init_state_maps(CHARSET_INFO *cs)
68
unsigned char *state_map;
69
unsigned char *ident_map;
62
if (!(cs->state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
71
if (!(cs->state_map= (unsigned char*) cs_alloc(256)))
65
if (!(cs->ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
74
if (!(cs->ident_map= (unsigned char*) cs_alloc(256)))
68
77
state_map= cs->state_map;
69
78
ident_map= cs->ident_map;
71
80
/* Fill state_map with states to get a faster parser */
72
81
for (i=0; i < 256 ; i++)
74
83
if (my_isalpha(cs,i))
75
state_map[i]=(uchar) MY_LEX_IDENT;
84
state_map[i]=(unsigned char) MY_LEX_IDENT;
76
85
else if (my_isdigit(cs,i))
77
state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
78
#if defined(USE_MB) && defined(USE_MB_IDENT)
86
state_map[i]=(unsigned char) MY_LEX_NUMBER_IDENT;
79
87
else if (my_mbcharlen(cs, i)>1)
80
state_map[i]=(uchar) MY_LEX_IDENT;
88
state_map[i]=(unsigned char) MY_LEX_IDENT;
82
89
else if (my_isspace(cs,i))
83
state_map[i]=(uchar) MY_LEX_SKIP;
90
state_map[i]=(unsigned char) MY_LEX_SKIP;
85
state_map[i]=(uchar) MY_LEX_CHAR;
92
state_map[i]=(unsigned char) MY_LEX_CHAR;
87
state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) MY_LEX_IDENT;
88
state_map[(uchar)'\'']=(uchar) MY_LEX_STRING;
89
state_map[(uchar)'.']=(uchar) MY_LEX_REAL_OR_POINT;
90
state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) MY_LEX_CMP_OP;
91
state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP;
92
state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL;
93
state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT;
94
state_map[(uchar)';']=(uchar) MY_LEX_SEMICOLON;
95
state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR;
96
state_map[0]=(uchar) MY_LEX_EOL;
97
state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE;
98
state_map[(uchar)'/']= (uchar) MY_LEX_LONG_COMMENT;
99
state_map[(uchar)'*']= (uchar) MY_LEX_END_LONG_COMMENT;
100
state_map[(uchar)'@']= (uchar) MY_LEX_USER_END;
101
state_map[(uchar) '`']= (uchar) MY_LEX_USER_VARIABLE_DELIMITER;
102
state_map[(uchar)'"']= (uchar) MY_LEX_STRING_OR_DELIMITER;
94
state_map[(unsigned char)'_']=state_map[(unsigned char)'$']=(unsigned char) MY_LEX_IDENT;
95
state_map[(unsigned char)'\'']=(unsigned char) MY_LEX_STRING;
96
state_map[(unsigned char)'.']=(unsigned char) MY_LEX_REAL_OR_POINT;
97
state_map[(unsigned char)'>']=state_map[(unsigned char)'=']=state_map[(unsigned char)'!']= (unsigned char) MY_LEX_CMP_OP;
98
state_map[(unsigned char)'<']= (unsigned char) MY_LEX_LONG_CMP_OP;
99
state_map[(unsigned char)'&']=state_map[(unsigned char)'|']=(unsigned char) MY_LEX_BOOL;
100
state_map[(unsigned char)'#']=(unsigned char) MY_LEX_COMMENT;
101
state_map[(unsigned char)';']=(unsigned char) MY_LEX_SEMICOLON;
102
state_map[(unsigned char)':']=(unsigned char) MY_LEX_SET_VAR;
103
state_map[0]=(unsigned char) MY_LEX_EOL;
104
state_map[(unsigned char)'\\']= (unsigned char) MY_LEX_ESCAPE;
105
state_map[(unsigned char)'/']= (unsigned char) MY_LEX_LONG_COMMENT;
106
state_map[(unsigned char)'*']= (unsigned char) MY_LEX_END_LONG_COMMENT;
107
state_map[(unsigned char)'@']= (unsigned char) MY_LEX_USER_END;
108
state_map[(unsigned char) '`']= (unsigned char) MY_LEX_USER_VARIABLE_DELIMITER;
109
state_map[(unsigned char)'"']= (unsigned char) MY_LEX_STRING_OR_DELIMITER;
105
112
Create a second map to make it faster to find identifiers
107
114
for (i=0; i < 256 ; i++)
109
ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
116
ident_map[i]= (unsigned char) (state_map[i] == MY_LEX_IDENT ||
110
117
state_map[i] == MY_LEX_NUMBER_IDENT);
113
120
/* Special handling of hex and binary strings */
114
state_map[(uchar)'x']= state_map[(uchar)'X']= (uchar) MY_LEX_IDENT_OR_HEX;
115
state_map[(uchar)'b']= state_map[(uchar)'B']= (uchar) MY_LEX_IDENT_OR_BIN;
120
static void simple_cs_init_functions(CHARSET_INFO *cs)
122
if (cs->state & MY_CS_BINSORT)
123
cs->coll= &my_collation_8bit_bin_handler;
125
cs->coll= &my_collation_8bit_simple_ci_handler;
127
cs->cset= &my_charset_8bit_handler;
132
static int cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from)
134
to->number= from->number ? from->number : to->number;
137
if (!(to->csname= my_once_strdup(from->csname,MYF(MY_WME))))
141
if (!(to->name= my_once_strdup(from->name,MYF(MY_WME))))
145
if (!(to->comment= my_once_strdup(from->comment,MYF(MY_WME))))
150
if (!(to->ctype= (uchar*) my_once_memdup((char*) from->ctype,
151
MY_CS_CTYPE_TABLE_SIZE,
154
if (init_state_maps(to))
158
if (!(to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower,
159
MY_CS_TO_LOWER_TABLE_SIZE,
164
if (!(to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper,
165
MY_CS_TO_UPPER_TABLE_SIZE,
168
if (from->sort_order)
170
if (!(to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order,
171
MY_CS_SORT_ORDER_TABLE_SIZE,
176
if (from->tab_to_uni)
178
uint sz= MY_CS_TO_UNI_TABLE_SIZE*sizeof(uint16_t);
179
if (!(to->tab_to_uni= (uint16_t*) my_once_memdup((char*)from->tab_to_uni,
184
if (!(to->tailoring= my_once_strdup(from->tailoring,MYF(MY_WME))))
195
static bool simple_cs_is_full(CHARSET_INFO *cs)
197
return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper &&
199
(cs->number && cs->name &&
200
(cs->sort_order || (cs->state & MY_CS_BINSORT) )));
205
copy_uca_collation(CHARSET_INFO *to, CHARSET_INFO *from)
207
to->cset= from->cset;
208
to->coll= from->coll;
209
to->strxfrm_multiply= from->strxfrm_multiply;
210
to->min_sort_char= from->min_sort_char;
211
to->max_sort_char= from->max_sort_char;
212
to->mbminlen= from->mbminlen;
213
to->mbmaxlen= from->mbmaxlen;
217
static int add_collation(CHARSET_INFO *cs)
219
if (cs->name && (cs->number ||
220
(cs->number=get_collation_number_internal(cs->name))))
222
if (!all_charsets[cs->number])
224
if (!(all_charsets[cs->number]=
225
(CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),MYF(0))))
227
memset(all_charsets[cs->number], 0, sizeof(CHARSET_INFO));
230
if (cs->primary_number == cs->number)
231
cs->state |= MY_CS_PRIMARY;
233
if (cs->binary_number == cs->number)
234
cs->state |= MY_CS_BINSORT;
236
all_charsets[cs->number]->state|= cs->state;
238
if (!(all_charsets[cs->number]->state & MY_CS_COMPILED))
240
CHARSET_INFO *newcs= all_charsets[cs->number];
241
if (cs_copy_data(all_charsets[cs->number],cs))
244
newcs->levels_for_compare= 1;
245
newcs->levels_for_order= 1;
247
if (!strcmp(cs->csname,"ucs2") )
249
#if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS)
250
copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci);
251
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
254
else if (!strcmp(cs->csname, "utf8"))
256
#if defined (HAVE_CHARSET_utf8mb3) && defined(HAVE_UCA_COLLATIONS)
257
copy_uca_collation(newcs, &my_charset_utf8mb4_unicode_ci);
258
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED;
261
else if (!strcmp(cs->csname, "utf8mb3"))
263
#if defined (HAVE_CHARSET_utf8mb3) && defined(HAVE_UCA_COLLATIONS)
264
copy_uca_collation(newcs, &my_charset_utf8mb3_unicode_ci);
265
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED;
268
else if (!strcmp(cs->csname, "utf16"))
270
#if defined (HAVE_CHARSET_utf16) && defined(HAVE_UCA_COLLATIONS)
271
copy_uca_collation(newcs, &my_charset_utf16_unicode_ci);
272
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
275
else if (!strcmp(cs->csname, "utf32"))
277
#if defined (HAVE_CHARSET_utf32) && defined(HAVE_UCA_COLLATIONS)
278
copy_uca_collation(newcs, &my_charset_utf32_unicode_ci);
279
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
284
uchar *sort_order= all_charsets[cs->number]->sort_order;
285
simple_cs_init_functions(all_charsets[cs->number]);
288
if (simple_cs_is_full(all_charsets[cs->number]))
290
all_charsets[cs->number]->state |= MY_CS_LOADED;
292
all_charsets[cs->number]->state|= MY_CS_AVAILABLE;
295
Check if case sensitive sort order: A < a < B.
296
We need MY_CS_FLAG for regex library, and for
297
case sensitivity flag for 5.0 client protocol,
298
to support isCaseSensitive() method in JDBC driver
300
if (sort_order && sort_order['A'] < sort_order['a'] &&
301
sort_order['a'] < sort_order['B'])
302
all_charsets[cs->number]->state|= MY_CS_CSSORT;
304
if (my_charset_is_8bit_pure_ascii(all_charsets[cs->number]))
305
all_charsets[cs->number]->state|= MY_CS_PUREASCII;
306
if (!my_charset_is_ascii_compatible(cs))
307
all_charsets[cs->number]->state|= MY_CS_NONASCII;
313
We need the below to make get_charset_name()
314
and get_charset_number() working even if a
315
character set has not been really incompiled.
316
The above functions are used for example
317
in error message compiler extra/comp_err.c.
318
If a character set was compiled, this information
319
will get lost and overwritten in add_compiled_collation().
321
CHARSET_INFO *dst= all_charsets[cs->number];
322
dst->number= cs->number;
324
if (!(dst->comment= my_once_strdup(cs->comment,MYF(MY_WME))))
326
if (cs->csname && !dst->csname)
327
if (!(dst->csname= my_once_strdup(cs->csname,MYF(MY_WME))))
329
if (cs->name && !dst->name)
330
if (!(dst->name= my_once_strdup(cs->name,MYF(MY_WME))))
334
cs->primary_number= 0;
335
cs->binary_number= 0;
338
cs->sort_order= NULL;
345
#define MY_MAX_ALLOWED_BUF 1024*1024
346
#define MY_CHARSET_INDEX "Index.xml"
348
const char *charsets_dir= NULL;
349
static int charset_initialized=0;
352
static bool my_read_charset_file(const char *filename, myf myflags)
357
struct stat stat_info;
359
if (stat(filename, &stat_info) ||
360
((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) ||
361
!(buf= (uchar*) my_malloc(len,myflags)))
364
if ((fd=my_open(filename,O_RDONLY,myflags)) < 0)
366
tmp_len=my_read(fd, buf, len, myflags);
367
my_close(fd,myflags);
371
if (my_parse_charset_xml((char*) buf,len,add_collation))
374
printf("ERROR at line %d pos %d '%s'\n",
375
my_xml_error_lineno(&p)+1,
376
my_xml_error_pos(&p),
377
my_xml_error_string(&p));
381
my_free(buf, myflags);
385
my_free(buf, myflags);
390
char *get_charsets_dir(char *buf)
392
const char *sharedir= SHAREDIR;
395
if (charsets_dir != NULL)
396
strmake(buf, charsets_dir, FN_REFLEN-1);
399
if (test_if_hard_path(sharedir) ||
400
is_prefix(sharedir, DEFAULT_CHARSET_HOME))
401
strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
403
strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
406
res= convert_dirname(buf,buf,NullS);
121
state_map[(unsigned char)'x']= state_map[(unsigned char)'X']= (unsigned char) MY_LEX_IDENT_OR_HEX;
122
state_map[(unsigned char)'b']= state_map[(unsigned char)'B']= (unsigned char) MY_LEX_IDENT_OR_BIN;
127
static bool charset_initialized= false;
410
129
CHARSET_INFO *all_charsets[256];
411
const CHARSET_INFO *default_charset_info = &my_charset_latin1;
130
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
413
132
void add_compiled_collation(CHARSET_INFO * cs)
416
135
cs->state|= MY_CS_AVAILABLE;
419
static void *cs_alloc(size_t size)
138
void *cs_alloc(size_t size)
421
return my_once_alloc(size, MYF(MY_WME));
140
void *ptr= malloc(size);
142
memory_vector.push_back(ptr);
425
149
static bool init_available_charsets(myf myflags)
427
char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
430
153
We have to use charset_initialized to not lock on THR_LOCK_charset
431
154
inside get_internal_charset...
433
if (!charset_initialized)
156
if (charset_initialized == false)
435
158
CHARSET_INFO **cs;
437
To make things thread safe we are not allowing other threads to interfere
438
while we may changing the cs_info_table
440
pthread_mutex_lock(&THR_LOCK_charset);
441
if (!charset_initialized)
159
memset(&all_charsets, 0, sizeof(all_charsets));
160
init_compiled_charsets(myflags);
162
/* Copy compiled charsets */
163
for (cs=all_charsets;
164
cs < all_charsets+array_elements(all_charsets)-1 ;
443
memset(&all_charsets, 0, sizeof(all_charsets));
444
init_compiled_charsets(myflags);
446
/* Copy compiled charsets */
447
for (cs=all_charsets;
448
cs < all_charsets+array_elements(all_charsets)-1 ;
454
if (init_state_maps(*cs))
170
if (init_state_maps(*cs))
459
stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
460
error= my_read_charset_file(fname,myflags);
461
charset_initialized=1;
463
pthread_mutex_unlock(&THR_LOCK_charset);
175
charset_initialized= true;
177
assert(charset_initialized);
469
183
void free_charsets(void)
471
charset_initialized=0;
185
charset_initialized= true;
187
while (memory_vector.empty() == false)
189
void *ptr= memory_vector.back();
190
memory_vector.pop_back();
193
memory_vector.clear();
475
uint get_collation_number(const char *name)
198
uint32_t get_collation_number(const char *name)
477
200
init_available_charsets(MYF(0));
478
201
return get_collation_number_internal(name);
482
uint get_charset_number(const char *charset_name, uint cs_flags)
205
uint32_t get_charset_number(const char *charset_name, uint32_t cs_flags)
484
207
CHARSET_INFO **cs;
485
208
init_available_charsets(MYF(0));
487
210
for (cs= all_charsets;
488
211
cs < all_charsets+array_elements(all_charsets)-1 ;
491
214
if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
492
!my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
215
!my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
493
216
return cs[0]->number;
499
const char *get_charset_name(uint charset_number)
222
const char *get_charset_name(uint32_t charset_number)
501
224
const CHARSET_INFO *cs;
502
225
init_available_charsets(MYF(0));
536
256
cs->state|= MY_CS_READY;
538
pthread_mutex_unlock(&THR_LOCK_charset);
543
const const CHARSET_INFO *get_charset(uint cs_number, myf flags)
263
const CHARSET_INFO *get_charset(uint32_t cs_number)
545
265
const CHARSET_INFO *cs;
546
266
if (cs_number == default_charset_info->number)
547
267
return default_charset_info;
549
269
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
551
271
if (!cs_number || cs_number >= array_elements(all_charsets)-1)
554
cs=get_internal_charset(cs_number, flags);
556
if (!cs && (flags & MY_WME))
558
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
559
stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
561
int10_to_str(cs_number, cs_string+1, 10);
562
my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
274
cs= get_internal_charset(cs_number);
567
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
279
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
570
282
const CHARSET_INFO *cs;
571
283
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
573
cs_number=get_collation_number(cs_name);
574
cs= cs_number ? get_internal_charset(cs_number,flags) : NULL;
576
if (!cs && (flags & MY_WME))
578
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
579
stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
580
my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
285
cs_number= get_collation_number(cs_name);
286
cs= cs_number ? get_internal_charset(cs_number) : NULL;
587
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
292
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
592
295
const CHARSET_INFO *cs;
594
297
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
596
299
cs_number= get_charset_number(cs_name, cs_flags);
597
cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
599
if (!cs && (flags & MY_WME))
601
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
602
stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
603
my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
300
cs= cs_number ? get_internal_charset(cs_number) : NULL;
611
Resolve character set by the character set name (utf8, latin1, ...).
613
The function tries to resolve character set by the specified name. If
614
there is character set with the given name, it is assigned to the "cs"
615
parameter and false is returned. If there is no such character set,
616
"default_cs" is assigned to the "cs" and true is returned.
618
@param[in] cs_name Character set name.
619
@param[in] default_cs Default character set.
620
@param[out] cs Variable to store character set.
622
@return false if character set was resolved successfully; true if there
623
is no character set with given name.
626
bool resolve_charset(const char *cs_name,
627
const CHARSET_INFO *default_cs,
628
const CHARSET_INFO **cs)
630
*cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
643
Resolve collation by the collation name (utf8_general_ci, ...).
645
The function tries to resolve collation by the specified name. If there
646
is collation with the given name, it is assigned to the "cl" parameter
647
and false is returned. If there is no such collation, "default_cl" is
648
assigned to the "cl" and true is returned.
650
@param[out] cl Variable to store collation.
651
@param[in] cl_name Collation name.
652
@param[in] default_cl Default collation.
654
@return false if collation was resolved successfully; true if there is no
655
collation with given name.
658
bool resolve_collation(const char *cl_name,
659
const CHARSET_INFO *default_cl,
660
const CHARSET_INFO **cl)
662
*cl= get_charset_by_name(cl_name, MYF(0));
675
Escape string with backslashes (\)
678
escape_string_for_drizzle()
679
charset_info Charset of the strings
680
to Buffer for escaped string
681
to_length Length of destination buffer, or 0
682
from The string to escape
683
length The length of the string to escape
686
This escapes the contents of a string by adding backslashes before special
687
characters, and turning others into specific escape sequences, such as
688
turning newlines into \n and null bytes into \0.
691
To maintain compatibility with the old C API, to_length may be 0 to mean
695
(size_t) -1 The escaped string did not fit in the to buffer
696
# The length of the escaped string
699
size_t escape_string_for_drizzle(const CHARSET_INFO *charset_info,
700
char *to, size_t to_length,
701
const char *from, size_t length)
703
const char *to_start= to;
704
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
705
bool overflow= false;
707
bool use_mb_flag= use_mb(charset_info);
709
for (end= from + length; from < end; from++)
714
if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
716
if (to + tmp_length > to_end)
727
If the next character appears to begin a multi-byte character, we
728
escape that first byte of that apparent multi-byte character. (The
729
character just looks like a multi-byte character -- if it were actually
730
a multi-byte character, it would have been passed through in the test
733
Without this check, we can create a problem by converting an invalid
734
multi-byte character into a valid one. For example, 0xbf27 is not
735
a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
737
if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
742
case 0: /* Must be escaped for 'mysql' */
745
case '\n': /* Must be escaped for logs */
757
case '"': /* Better safe than sorry */
760
case '\032': /* This gives problems on Win32 */
785
return overflow ? (size_t) -1 : (size_t) (to - to_start);
789
#ifdef BACKSLASH_MBTAIL
790
static CHARSET_INFO *fs_cset_cache= NULL;
792
CHARSET_INFO *fs_character_set()
797
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
798
buf+2, sizeof(buf)-3);
800
We cannot call get_charset_by_name here
801
because fs_character_set() is executed before
802
LOCK_THD_charset mutex initialization, which
803
is used inside get_charset_by_name.
804
As we're now interested in cp932 only,
805
let's just detect it using strcmp().
807
fs_cset_cache= !strcmp(buf, "cp932") ?
808
&my_charset_cp932_japanese_ci : &my_charset_bin;
810
return fs_cset_cache;
815
307
Escape apostrophes by doubling them up