~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Stewart Smith
  • Date: 2008-07-13 08:00:16 UTC
  • mto: (210.1.1 drizzle)
  • mto: This revision was merged to the branch mainline in revision 211.
  • Revision ID: stewart@flamingspork.com-20080713080016-8qtjv9ypt42azzr6
CRC32() as UDF

Show diffs side-by-side

added added

removed removed

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