~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "mysys_priv.h"
 
17
#include "mysys_err.h"
 
18
#include <m_ctype.h>
 
19
#include <m_string.h>
 
20
#include <my_dir.h>
 
21
#include <my_xml.h>
 
22
 
 
23
 
 
24
/*
 
25
  The code below implements this functionality:
 
26
  
 
27
    - Initializing charset related structures
 
28
    - Loading dynamic charsets
 
29
    - Searching for a proper CHARSET_INFO 
 
30
      using charset name, collation name or collation ID
 
31
    - Setting server default character set
 
32
*/
 
33
 
 
34
my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
 
35
{
 
36
  return ((cs1 == cs2) || !strcmp(cs1->csname,cs2->csname));
 
37
}
 
38
 
 
39
 
 
40
static uint
 
41
get_collation_number_internal(const char *name)
 
42
{
 
43
  CHARSET_INFO **cs;
 
44
  for (cs= all_charsets;
 
45
       cs < all_charsets+array_elements(all_charsets)-1 ;
 
46
       cs++)
 
47
  {
 
48
    if ( cs[0] && cs[0]->name && 
 
49
         !my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
 
50
      return cs[0]->number;
 
51
  }  
 
52
  return 0;
 
53
}
 
54
 
 
55
 
 
56
static my_bool init_state_maps(CHARSET_INFO *cs)
 
57
{
 
58
  uint i;
 
59
  uchar *state_map;
 
60
  uchar *ident_map;
 
61
 
 
62
  if (!(cs->state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
 
63
    return 1;
 
64
    
 
65
  if (!(cs->ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
 
66
    return 1;
 
67
 
 
68
  state_map= cs->state_map;
 
69
  ident_map= cs->ident_map;
 
70
  
 
71
  /* Fill state_map with states to get a faster parser */
 
72
  for (i=0; i < 256 ; i++)
 
73
  {
 
74
    if (my_isalpha(cs,i))
 
75
      state_map[i]=(uchar) MY_LEX_IDENT;
 
76
    else if (my_isdigit(cs,i))
 
77
      state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
 
78
#if defined(USE_MB) && defined(USE_MB_IDENT)
 
79
    else if (my_mbcharlen(cs, i)>1)
 
80
      state_map[i]=(uchar) MY_LEX_IDENT;
 
81
#endif
 
82
    else if (my_isspace(cs,i))
 
83
      state_map[i]=(uchar) MY_LEX_SKIP;
 
84
    else
 
85
      state_map[i]=(uchar) MY_LEX_CHAR;
 
86
  }
 
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;
 
103
 
 
104
  /*
 
105
    Create a second map to make it faster to find identifiers
 
106
  */
 
107
  for (i=0; i < 256 ; i++)
 
108
  {
 
109
    ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
 
110
                           state_map[i] == MY_LEX_NUMBER_IDENT);
 
111
  }
 
112
 
 
113
  /* 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;
 
116
  state_map[(uchar)'n']= state_map[(uchar)'N']= (uchar) MY_LEX_IDENT_OR_NCHAR;
 
117
  return 0;
 
118
}
 
119
 
 
120
 
 
121
static void simple_cs_init_functions(CHARSET_INFO *cs)
 
122
{
 
123
  if (cs->state & MY_CS_BINSORT)
 
124
    cs->coll= &my_collation_8bit_bin_handler;
 
125
  else
 
126
    cs->coll= &my_collation_8bit_simple_ci_handler;
 
127
  
 
128
  cs->cset= &my_charset_8bit_handler;
 
129
}
 
130
 
 
131
 
 
132
 
 
133
static int cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from)
 
134
{
 
135
  to->number= from->number ? from->number : to->number;
 
136
 
 
137
  if (from->csname)
 
138
    if (!(to->csname= my_once_strdup(from->csname,MYF(MY_WME))))
 
139
      goto err;
 
140
  
 
141
  if (from->name)
 
142
    if (!(to->name= my_once_strdup(from->name,MYF(MY_WME))))
 
143
      goto err;
 
144
  
 
145
  if (from->comment)
 
146
    if (!(to->comment= my_once_strdup(from->comment,MYF(MY_WME))))
 
147
      goto err;
 
148
  
 
149
  if (from->ctype)
 
150
  {
 
151
    if (!(to->ctype= (uchar*) my_once_memdup((char*) from->ctype,
 
152
                                             MY_CS_CTYPE_TABLE_SIZE,
 
153
                                             MYF(MY_WME))))
 
154
      goto err;
 
155
    if (init_state_maps(to))
 
156
      goto err;
 
157
  }
 
158
  if (from->to_lower)
 
159
    if (!(to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower,
 
160
                                                MY_CS_TO_LOWER_TABLE_SIZE,
 
161
                                                MYF(MY_WME))))
 
162
      goto err;
 
163
 
 
164
  if (from->to_upper)
 
165
    if (!(to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper,
 
166
                                                MY_CS_TO_UPPER_TABLE_SIZE,
 
167
                                                MYF(MY_WME))))
 
168
      goto err;
 
169
  if (from->sort_order)
 
170
  {
 
171
    if (!(to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order,
 
172
                                                  MY_CS_SORT_ORDER_TABLE_SIZE,
 
173
                                                  MYF(MY_WME))))
 
174
      goto err;
 
175
 
 
176
  }
 
177
  if (from->tab_to_uni)
 
178
  {
 
179
    uint sz= MY_CS_TO_UNI_TABLE_SIZE*sizeof(uint16);
 
180
    if (!(to->tab_to_uni= (uint16*)  my_once_memdup((char*)from->tab_to_uni,
 
181
                                                    sz, MYF(MY_WME))))
 
182
      goto err;
 
183
  }
 
184
  if (from->tailoring)
 
185
    if (!(to->tailoring= my_once_strdup(from->tailoring,MYF(MY_WME))))
 
186
      goto err;
 
187
 
 
188
  return 0;
 
189
 
 
190
err:
 
191
  return 1;
 
192
}
 
193
 
 
194
 
 
195
 
 
196
static my_bool simple_cs_is_full(CHARSET_INFO *cs)
 
197
{
 
198
  return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper &&
 
199
           cs->to_lower) &&
 
200
          (cs->number && cs->name &&
 
201
          (cs->sort_order || (cs->state & MY_CS_BINSORT) )));
 
202
}
 
203
 
 
204
 
 
205
static void
 
206
copy_uca_collation(CHARSET_INFO *to, CHARSET_INFO *from)
 
207
{
 
208
  to->cset= from->cset;
 
209
  to->coll= from->coll;
 
210
  to->strxfrm_multiply= from->strxfrm_multiply;
 
211
  to->min_sort_char= from->min_sort_char;
 
212
  to->max_sort_char= from->max_sort_char;
 
213
  to->mbminlen= from->mbminlen;
 
214
  to->mbmaxlen= from->mbmaxlen;
 
215
  to->state|= MY_CS_AVAILABLE | MY_CS_LOADED |
 
216
              MY_CS_STRNXFRM  | MY_CS_UNICODE;
 
217
}
 
218
 
 
219
 
 
220
static int add_collation(CHARSET_INFO *cs)
 
221
{
 
222
  if (cs->name && (cs->number ||
 
223
                   (cs->number=get_collation_number_internal(cs->name))) &&
 
224
      cs->number < array_elements(all_charsets))
 
225
  {
 
226
    if (!all_charsets[cs->number])
 
227
    {
 
228
      if (!(all_charsets[cs->number]=
 
229
         (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),MYF(0))))
 
230
        return MY_XML_ERROR;
 
231
      bzero((void*)all_charsets[cs->number],sizeof(CHARSET_INFO));
 
232
    }
 
233
    
 
234
    if (cs->primary_number == cs->number)
 
235
      cs->state |= MY_CS_PRIMARY;
 
236
      
 
237
    if (cs->binary_number == cs->number)
 
238
      cs->state |= MY_CS_BINSORT;
 
239
    
 
240
    all_charsets[cs->number]->state|= cs->state;
 
241
    
 
242
    if (!(all_charsets[cs->number]->state & MY_CS_COMPILED))
 
243
    {
 
244
      CHARSET_INFO *newcs= all_charsets[cs->number];
 
245
      if (cs_copy_data(all_charsets[cs->number],cs))
 
246
        return MY_XML_ERROR;
 
247
 
 
248
      if (!strcmp(cs->csname,"ucs2") )
 
249
      {
 
250
#if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS)
 
251
        copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci);
 
252
#endif        
 
253
      }
 
254
      else if (!strcmp(cs->csname, "utf8"))
 
255
      {
 
256
#if defined (HAVE_CHARSET_utf8) && defined(HAVE_UCA_COLLATIONS)
 
257
        copy_uca_collation(newcs, &my_charset_utf8_unicode_ci);
 
258
#endif
 
259
      }
 
260
      else
 
261
      {
 
262
        uchar *sort_order= all_charsets[cs->number]->sort_order;
 
263
        simple_cs_init_functions(all_charsets[cs->number]);
 
264
        newcs->mbminlen= 1;
 
265
        newcs->mbmaxlen= 1;
 
266
        if (simple_cs_is_full(all_charsets[cs->number]))
 
267
        {
 
268
          all_charsets[cs->number]->state |= MY_CS_LOADED;
 
269
        }
 
270
        all_charsets[cs->number]->state|= MY_CS_AVAILABLE;
 
271
        
 
272
        /*
 
273
          Check if case sensitive sort order: A < a < B.
 
274
          We need MY_CS_FLAG for regex library, and for
 
275
          case sensitivity flag for 5.0 client protocol,
 
276
          to support isCaseSensitive() method in JDBC driver 
 
277
        */
 
278
        if (sort_order && sort_order['A'] < sort_order['a'] &&
 
279
                          sort_order['a'] < sort_order['B'])
 
280
          all_charsets[cs->number]->state|= MY_CS_CSSORT; 
 
281
 
 
282
        if (my_charset_is_8bit_pure_ascii(all_charsets[cs->number]))
 
283
          all_charsets[cs->number]->state|= MY_CS_PUREASCII;
 
284
      }
 
285
    }
 
286
    else
 
287
    {
 
288
      /*
 
289
        We need the below to make get_charset_name()
 
290
        and get_charset_number() working even if a
 
291
        character set has not been really incompiled.
 
292
        The above functions are used for example
 
293
        in error message compiler extra/comp_err.c.
 
294
        If a character set was compiled, this information
 
295
        will get lost and overwritten in add_compiled_collation().
 
296
      */
 
297
      CHARSET_INFO *dst= all_charsets[cs->number];
 
298
      dst->number= cs->number;
 
299
      if (cs->comment)
 
300
        if (!(dst->comment= my_once_strdup(cs->comment,MYF(MY_WME))))
 
301
          return MY_XML_ERROR;
 
302
      if (cs->csname)
 
303
        if (!(dst->csname= my_once_strdup(cs->csname,MYF(MY_WME))))
 
304
          return MY_XML_ERROR;
 
305
      if (cs->name)
 
306
        if (!(dst->name= my_once_strdup(cs->name,MYF(MY_WME))))
 
307
          return MY_XML_ERROR;
 
308
    }
 
309
    cs->number= 0;
 
310
    cs->primary_number= 0;
 
311
    cs->binary_number= 0;
 
312
    cs->name= NULL;
 
313
    cs->state= 0;
 
314
    cs->sort_order= NULL;
 
315
    cs->state= 0;
 
316
  }
 
317
  return MY_XML_OK;
 
318
}
 
319
 
 
320
 
 
321
#define MY_MAX_ALLOWED_BUF 1024*1024
 
322
#define MY_CHARSET_INDEX "Index.xml"
 
323
 
 
324
const char *charsets_dir= NULL;
 
325
 
 
326
 
 
327
static my_bool my_read_charset_file(const char *filename, myf myflags)
 
328
{
 
329
  uchar *buf;
 
330
  int  fd;
 
331
  size_t len, tmp_len;
 
332
  MY_STAT stat_info;
 
333
  
 
334
  if (!my_stat(filename, &stat_info, MYF(myflags)) ||
 
335
       ((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) ||
 
336
       !(buf= (uchar*) my_malloc(len,myflags)))
 
337
    return TRUE;
 
338
  
 
339
  if ((fd=my_open(filename,O_RDONLY,myflags)) < 0)
 
340
    goto error;
 
341
  tmp_len=my_read(fd, buf, len, myflags);
 
342
  my_close(fd,myflags);
 
343
  if (tmp_len != len)
 
344
    goto error;
 
345
  
 
346
  if (my_parse_charset_xml((char*) buf,len,add_collation))
 
347
  {
 
348
#ifdef NOT_YET
 
349
    printf("ERROR at line %d pos %d '%s'\n",
 
350
           my_xml_error_lineno(&p)+1,
 
351
           my_xml_error_pos(&p),
 
352
           my_xml_error_string(&p));
 
353
#endif
 
354
  }
 
355
  
 
356
  my_free(buf, myflags);
 
357
  return FALSE;
 
358
 
 
359
error:
 
360
  my_free(buf, myflags);
 
361
  return TRUE;
 
362
}
 
363
 
 
364
 
 
365
char *get_charsets_dir(char *buf)
 
366
{
 
367
  const char *sharedir= SHAREDIR;
 
368
  char *res;
 
369
  DBUG_ENTER("get_charsets_dir");
 
370
 
 
371
  if (charsets_dir != NULL)
 
372
    strmake(buf, charsets_dir, FN_REFLEN-1);
 
373
  else
 
374
  {
 
375
    if (test_if_hard_path(sharedir) ||
 
376
        is_prefix(sharedir, DEFAULT_CHARSET_HOME))
 
377
      strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
 
378
    else
 
379
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
 
380
              NullS);
 
381
  }
 
382
  res= convert_dirname(buf,buf,NullS);
 
383
  DBUG_PRINT("info",("charsets dir: '%s'", buf));
 
384
  DBUG_RETURN(res);
 
385
}
 
386
 
 
387
CHARSET_INFO *all_charsets[256]={NULL};
 
388
CHARSET_INFO *default_charset_info = &my_charset_latin1;
 
389
 
 
390
void add_compiled_collation(CHARSET_INFO *cs)
 
391
{
 
392
  all_charsets[cs->number]= cs;
 
393
  cs->state|= MY_CS_AVAILABLE;
 
394
}
 
395
 
 
396
static void *cs_alloc(size_t size)
 
397
{
 
398
  return my_once_alloc(size, MYF(MY_WME));
 
399
}
 
400
 
 
401
 
 
402
static my_pthread_once_t charsets_initialized= MY_PTHREAD_ONCE_INIT;
 
403
 
 
404
static void init_available_charsets(void)
 
405
{
 
406
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
407
  CHARSET_INFO **cs;
 
408
 
 
409
  bzero(&all_charsets,sizeof(all_charsets));
 
410
  init_compiled_charsets(MYF(0));
 
411
      
 
412
  /* Copy compiled charsets */
 
413
  for (cs=all_charsets;
 
414
       cs < all_charsets+array_elements(all_charsets)-1 ;
 
415
       cs++)
 
416
  {
 
417
    if (*cs)
 
418
    {
 
419
      if (cs[0]->ctype)
 
420
        if (init_state_maps(*cs))
 
421
          *cs= NULL;
 
422
    }
 
423
  }
 
424
      
 
425
  strmov(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
426
  my_read_charset_file(fname, MYF(0));
 
427
}
 
428
 
 
429
 
 
430
uint get_collation_number(const char *name)
 
431
{
 
432
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
433
  return get_collation_number_internal(name);
 
434
}
 
435
 
 
436
 
 
437
uint get_charset_number(const char *charset_name, uint cs_flags)
 
438
{
 
439
  CHARSET_INFO **cs;
 
440
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
441
  
 
442
  for (cs= all_charsets;
 
443
       cs < all_charsets+array_elements(all_charsets)-1 ;
 
444
       cs++)
 
445
  {
 
446
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
 
447
         !my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
 
448
      return cs[0]->number;
 
449
  }  
 
450
  return 0;
 
451
}
 
452
 
 
453
 
 
454
const char *get_charset_name(uint charset_number)
 
455
{
 
456
  CHARSET_INFO *cs;
 
457
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
458
 
 
459
  cs=all_charsets[charset_number];
 
460
  if (cs && (cs->number == charset_number) && cs->name )
 
461
    return (char*) cs->name;
 
462
  
 
463
  return (char*) "?";   /* this mimics find_type() */
 
464
}
 
465
 
 
466
 
 
467
static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
 
468
{
 
469
  char  buf[FN_REFLEN];
 
470
  CHARSET_INFO *cs;
 
471
 
 
472
  if ((cs= all_charsets[cs_number]))
 
473
  {
 
474
    if (cs->state & MY_CS_READY)  /* if CS is already initialized */
 
475
        return cs;
 
476
 
 
477
    /*
 
478
      To make things thread safe we are not allowing other threads to interfere
 
479
      while we may changing the cs_info_table
 
480
    */
 
481
    pthread_mutex_lock(&THR_LOCK_charset);
 
482
 
 
483
    if (!(cs->state & (MY_CS_COMPILED|MY_CS_LOADED))) /* if CS is not in memory */
 
484
    {
 
485
      strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
 
486
      my_read_charset_file(buf,flags);
 
487
    }
 
488
 
 
489
    if (cs->state & MY_CS_AVAILABLE)
 
490
    {
 
491
      if (!(cs->state & MY_CS_READY))
 
492
      {
 
493
        if ((cs->cset->init && cs->cset->init(cs, cs_alloc)) ||
 
494
            (cs->coll->init && cs->coll->init(cs, cs_alloc)))
 
495
          cs= NULL;
 
496
        else
 
497
          cs->state|= MY_CS_READY;
 
498
      }
 
499
    }
 
500
    else
 
501
      cs= NULL;
 
502
 
 
503
    pthread_mutex_unlock(&THR_LOCK_charset);
 
504
  }
 
505
  return cs;
 
506
}
 
507
 
 
508
 
 
509
CHARSET_INFO *get_charset(uint cs_number, myf flags)
 
510
{
 
511
  CHARSET_INFO *cs;
 
512
  if (cs_number == default_charset_info->number)
 
513
    return default_charset_info;
 
514
 
 
515
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
516
  
 
517
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
 
518
    return NULL;
 
519
  
 
520
  cs=get_internal_charset(cs_number, flags);
 
521
 
 
522
  if (!cs && (flags & MY_WME))
 
523
  {
 
524
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
 
525
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
526
    cs_string[0]='#';
 
527
    int10_to_str(cs_number, cs_string+1, 10);
 
528
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
 
529
  }
 
530
  return cs;
 
531
}
 
532
 
 
533
CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
 
534
{
 
535
  uint cs_number;
 
536
  CHARSET_INFO *cs;
 
537
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
538
 
 
539
  cs_number=get_collation_number(cs_name);
 
540
  cs= cs_number ? get_internal_charset(cs_number,flags) : NULL;
 
541
 
 
542
  if (!cs && (flags & MY_WME))
 
543
  {
 
544
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
545
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
546
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
 
547
  }
 
548
 
 
549
  return cs;
 
550
}
 
551
 
 
552
 
 
553
CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
554
                                    uint cs_flags,
 
555
                                    myf flags)
 
556
{
 
557
  uint cs_number;
 
558
  CHARSET_INFO *cs;
 
559
  DBUG_ENTER("get_charset_by_csname");
 
560
  DBUG_PRINT("enter",("name: '%s'", cs_name));
 
561
 
 
562
  my_pthread_once(&charsets_initialized, init_available_charsets);
 
563
 
 
564
  cs_number= get_charset_number(cs_name, cs_flags);
 
565
  cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
 
566
 
 
567
  if (!cs && (flags & MY_WME))
 
568
  {
 
569
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
570
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
571
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
 
572
  }
 
573
 
 
574
  DBUG_RETURN(cs);
 
575
}
 
576
 
 
577
 
 
578
/**
 
579
  Resolve character set by the character set name (utf8, latin1, ...).
 
580
 
 
581
  The function tries to resolve character set by the specified name. If
 
582
  there is character set with the given name, it is assigned to the "cs"
 
583
  parameter and FALSE is returned. If there is no such character set,
 
584
  "default_cs" is assigned to the "cs" and TRUE is returned.
 
585
 
 
586
  @param[in] cs_name    Character set name.
 
587
  @param[in] default_cs Default character set.
 
588
  @param[out] cs        Variable to store character set.
 
589
 
 
590
  @return FALSE if character set was resolved successfully; TRUE if there
 
591
  is no character set with given name.
 
592
*/
 
593
 
 
594
my_bool resolve_charset(const char *cs_name,
 
595
                        CHARSET_INFO *default_cs,
 
596
                        CHARSET_INFO **cs)
 
597
{
 
598
  *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
 
599
 
 
600
  if (*cs == NULL)
 
601
  {
 
602
    *cs= default_cs;
 
603
    return TRUE;
 
604
  }
 
605
 
 
606
  return FALSE;
 
607
}
 
608
 
 
609
 
 
610
/**
 
611
  Resolve collation by the collation name (utf8_general_ci, ...).
 
612
 
 
613
  The function tries to resolve collation by the specified name. If there
 
614
  is collation with the given name, it is assigned to the "cl" parameter
 
615
  and FALSE is returned. If there is no such collation, "default_cl" is
 
616
  assigned to the "cl" and TRUE is returned.
 
617
 
 
618
  @param[out] cl        Variable to store collation.
 
619
  @param[in] cl_name    Collation name.
 
620
  @param[in] default_cl Default collation.
 
621
 
 
622
  @return FALSE if collation was resolved successfully; TRUE if there is no
 
623
  collation with given name.
 
624
*/
 
625
 
 
626
my_bool resolve_collation(const char *cl_name,
 
627
                          CHARSET_INFO *default_cl,
 
628
                          CHARSET_INFO **cl)
 
629
{
 
630
  *cl= get_charset_by_name(cl_name, MYF(0));
 
631
 
 
632
  if (*cl == NULL)
 
633
  {
 
634
    *cl= default_cl;
 
635
    return TRUE;
 
636
  }
 
637
 
 
638
  return FALSE;
 
639
}
 
640
 
 
641
 
 
642
/*
 
643
  Escape string with backslashes (\)
 
644
 
 
645
  SYNOPSIS
 
646
    escape_string_for_mysql()
 
647
    charset_info        Charset of the strings
 
648
    to                  Buffer for escaped string
 
649
    to_length           Length of destination buffer, or 0
 
650
    from                The string to escape
 
651
    length              The length of the string to escape
 
652
 
 
653
  DESCRIPTION
 
654
    This escapes the contents of a string by adding backslashes before special
 
655
    characters, and turning others into specific escape sequences, such as
 
656
    turning newlines into \n and null bytes into \0.
 
657
 
 
658
  NOTE
 
659
    To maintain compatibility with the old C API, to_length may be 0 to mean
 
660
    "big enough"
 
661
 
 
662
  RETURN VALUES
 
663
    (size_t) -1 The escaped string did not fit in the to buffer
 
664
    #           The length of the escaped string
 
665
*/
 
666
 
 
667
size_t escape_string_for_mysql(CHARSET_INFO *charset_info,
 
668
                               char *to, size_t to_length,
 
669
                               const char *from, size_t length)
 
670
{
 
671
  const char *to_start= to;
 
672
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
 
673
  my_bool overflow= FALSE;
 
674
#ifdef USE_MB
 
675
  my_bool use_mb_flag= use_mb(charset_info);
 
676
#endif
 
677
  for (end= from + length; from < end; from++)
 
678
  {
 
679
    char escape= 0;
 
680
#ifdef USE_MB
 
681
    int tmp_length;
 
682
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
 
683
    {
 
684
      if (to + tmp_length > to_end)
 
685
      {
 
686
        overflow= TRUE;
 
687
        break;
 
688
      }
 
689
      while (tmp_length--)
 
690
        *to++= *from++;
 
691
      from--;
 
692
      continue;
 
693
    }
 
694
    /*
 
695
     If the next character appears to begin a multi-byte character, we
 
696
     escape that first byte of that apparent multi-byte character. (The
 
697
     character just looks like a multi-byte character -- if it were actually
 
698
     a multi-byte character, it would have been passed through in the test
 
699
     above.)
 
700
 
 
701
     Without this check, we can create a problem by converting an invalid
 
702
     multi-byte character into a valid one. For example, 0xbf27 is not
 
703
     a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
 
704
    */
 
705
    if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
 
706
      escape= *from;
 
707
    else
 
708
#endif
 
709
    switch (*from) {
 
710
    case 0:                             /* Must be escaped for 'mysql' */
 
711
      escape= '0';
 
712
      break;
 
713
    case '\n':                          /* Must be escaped for logs */
 
714
      escape= 'n';
 
715
      break;
 
716
    case '\r':
 
717
      escape= 'r';
 
718
      break;
 
719
    case '\\':
 
720
      escape= '\\';
 
721
      break;
 
722
    case '\'':
 
723
      escape= '\'';
 
724
      break;
 
725
    case '"':                           /* Better safe than sorry */
 
726
      escape= '"';
 
727
      break;
 
728
    case '\032':                        /* This gives problems on Win32 */
 
729
      escape= 'Z';
 
730
      break;
 
731
    }
 
732
    if (escape)
 
733
    {
 
734
      if (to + 2 > to_end)
 
735
      {
 
736
        overflow= TRUE;
 
737
        break;
 
738
      }
 
739
      *to++= '\\';
 
740
      *to++= escape;
 
741
    }
 
742
    else
 
743
    {
 
744
      if (to + 1 > to_end)
 
745
      {
 
746
        overflow= TRUE;
 
747
        break;
 
748
      }
 
749
      *to++= *from;
 
750
    }
 
751
  }
 
752
  *to= 0;
 
753
  return overflow ? (size_t) -1 : (size_t) (to - to_start);
 
754
}
 
755
 
 
756
 
 
757
#ifdef BACKSLASH_MBTAIL
 
758
static CHARSET_INFO *fs_cset_cache= NULL;
 
759
 
 
760
CHARSET_INFO *fs_character_set()
 
761
{
 
762
  if (!fs_cset_cache)
 
763
  {
 
764
    char buf[10]= "cp";
 
765
    GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
 
766
                  buf+2, sizeof(buf)-3);
 
767
    /*
 
768
      We cannot call get_charset_by_name here
 
769
      because fs_character_set() is executed before
 
770
      LOCK_THD_charset mutex initialization, which
 
771
      is used inside get_charset_by_name.
 
772
      As we're now interested in cp932 only,
 
773
      let's just detect it using strcmp().
 
774
    */
 
775
    fs_cset_cache= !strcmp(buf, "cp932") ?
 
776
                   &my_charset_cp932_japanese_ci : &my_charset_bin;
 
777
  }
 
778
  return fs_cset_cache;
 
779
}
 
780
#endif
 
781
 
 
782
/*
 
783
  Escape apostrophes by doubling them up
 
784
 
 
785
  SYNOPSIS
 
786
    escape_quotes_for_mysql()
 
787
    charset_info        Charset of the strings
 
788
    to                  Buffer for escaped string
 
789
    to_length           Length of destination buffer, or 0
 
790
    from                The string to escape
 
791
    length              The length of the string to escape
 
792
 
 
793
  DESCRIPTION
 
794
    This escapes the contents of a string by doubling up any apostrophes that
 
795
    it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in
 
796
    effect on the server.
 
797
 
 
798
  NOTE
 
799
    To be consistent with escape_string_for_mysql(), to_length may be 0 to
 
800
    mean "big enough"
 
801
 
 
802
  RETURN VALUES
 
803
    ~0          The escaped string did not fit in the to buffer
 
804
    >=0         The length of the escaped string
 
805
*/
 
806
 
 
807
size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
 
808
                               char *to, size_t to_length,
 
809
                               const char *from, size_t length)
 
810
{
 
811
  const char *to_start= to;
 
812
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
 
813
  my_bool overflow= FALSE;
 
814
#ifdef USE_MB
 
815
  my_bool use_mb_flag= use_mb(charset_info);
 
816
#endif
 
817
  for (end= from + length; from < end; from++)
 
818
  {
 
819
#ifdef USE_MB
 
820
    int tmp_length;
 
821
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
 
822
    {
 
823
      if (to + tmp_length > to_end)
 
824
      {
 
825
        overflow= TRUE;
 
826
        break;
 
827
      }
 
828
      while (tmp_length--)
 
829
        *to++= *from++;
 
830
      from--;
 
831
      continue;
 
832
    }
 
833
    /*
 
834
      We don't have the same issue here with a non-multi-byte character being
 
835
      turned into a multi-byte character by the addition of an escaping
 
836
      character, because we are only escaping the ' character with itself.
 
837
     */
 
838
#endif
 
839
    if (*from == '\'')
 
840
    {
 
841
      if (to + 2 > to_end)
 
842
      {
 
843
        overflow= TRUE;
 
844
        break;
 
845
      }
 
846
      *to++= '\'';
 
847
      *to++= '\'';
 
848
    }
 
849
    else
 
850
    {
 
851
      if (to + 1 > to_end)
 
852
      {
 
853
        overflow= TRUE;
 
854
        break;
 
855
      }
 
856
      *to++= *from;
 
857
    }
 
858
  }
 
859
  *to= 0;
 
860
  return overflow ? (ulong)~0 : (ulong) (to - to_start);
 
861
}