~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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
 
 
 
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
119
347
#define MY_CHARSET_INDEX "Index.xml"
120
348
 
121
349
const char *charsets_dir= NULL;
122
350
static int charset_initialized=0;
123
351
 
124
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
  MY_STAT stat_info;
 
359
  
 
360
  if (!my_stat(filename, &stat_info, MYF(myflags)) ||
 
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
 
125
391
char *get_charsets_dir(char *buf)
126
392
{
 
393
  const char *sharedir= SHAREDIR;
127
394
  char *res;
 
395
  DBUG_ENTER("get_charsets_dir");
128
396
 
129
397
  if (charsets_dir != NULL)
130
 
    strncpy(buf, charsets_dir, FN_REFLEN-1);
 
398
    strmake(buf, charsets_dir, FN_REFLEN-1);
131
399
  else
132
400
  {
133
 
    if (test_if_hard_path(PKGDATADIR) ||
134
 
        is_prefix(PKGDATADIR, PREFIX))
135
 
      sprintf(buf,"%s/%s",PKGDATADIR,CHARSET_DIR);
 
401
    if (test_if_hard_path(sharedir) ||
 
402
        is_prefix(sharedir, DEFAULT_CHARSET_HOME))
 
403
      strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
136
404
    else
137
 
      sprintf(buf,"%s/%s/%s",PREFIX,PKGDATADIR,CHARSET_DIR);
 
405
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
 
406
              NullS);
138
407
  }
139
 
  res= convert_dirname(buf,buf,NULL);
140
 
  return(res);
 
408
  res= convert_dirname(buf,buf,NullS);
 
409
  DBUG_PRINT("info",("charsets dir: '%s'", buf));
 
410
  DBUG_RETURN(res);
141
411
}
142
412
 
143
413
CHARSET_INFO *all_charsets[256];
144
 
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
 
414
CHARSET_INFO *default_charset_info = &my_charset_latin1;
145
415
 
146
 
void add_compiled_collation(CHARSET_INFO * cs)
 
416
void add_compiled_collation(CHARSET_INFO *cs)
147
417
{
148
418
  all_charsets[cs->number]= cs;
149
419
  cs->state|= MY_CS_AVAILABLE;
150
420
}
151
421
 
152
 
void *cs_alloc(size_t size)
 
422
static void *cs_alloc(size_t size)
153
423
{
154
 
  return malloc(size);
 
424
  return my_once_alloc(size, MYF(MY_WME));
155
425
}
156
426
 
157
427
 
158
 
static bool init_available_charsets(myf myflags)
 
428
static my_bool init_available_charsets(myf myflags)
159
429
{
160
430
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
161
 
  bool error=false;
 
431
  my_bool error=FALSE;
162
432
  /*
163
433
    We have to use charset_initialized to not lock on THR_LOCK_charset
164
434
    inside get_internal_charset...
173
443
    pthread_mutex_lock(&THR_LOCK_charset);
174
444
    if (!charset_initialized)
175
445
    {
176
 
      memset(&all_charsets, 0, sizeof(all_charsets));
 
446
      bzero(&all_charsets,sizeof(all_charsets));
177
447
      init_compiled_charsets(myflags);
178
 
 
 
448
      
179
449
      /* Copy compiled charsets */
180
450
      for (cs=all_charsets;
181
451
           cs < all_charsets+array_elements(all_charsets)-1 ;
188
458
              *cs= NULL;
189
459
        }
190
460
      }
191
 
 
192
 
      strcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
461
      
 
462
      strmov(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
463
      error= my_read_charset_file(fname,myflags);
193
464
      charset_initialized=1;
194
465
    }
195
466
    pthread_mutex_unlock(&THR_LOCK_charset);
204
475
}
205
476
 
206
477
 
207
 
uint32_t get_collation_number(const char *name)
 
478
uint get_collation_number(const char *name)
208
479
{
209
480
  init_available_charsets(MYF(0));
210
481
  return get_collation_number_internal(name);
211
482
}
212
483
 
213
484
 
214
 
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)
215
486
{
216
487
  CHARSET_INFO **cs;
217
488
  init_available_charsets(MYF(0));
218
 
 
 
489
  
219
490
  for (cs= all_charsets;
220
491
       cs < all_charsets+array_elements(all_charsets)-1 ;
221
492
       cs++)
222
493
  {
223
494
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
224
 
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
 
495
         !my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
225
496
      return cs[0]->number;
226
 
  }
 
497
  }  
227
498
  return 0;
228
499
}
229
500
 
230
501
 
231
 
const char *get_charset_name(uint32_t charset_number)
 
502
const char *get_charset_name(uint charset_number)
232
503
{
233
 
  const CHARSET_INFO *cs;
 
504
  CHARSET_INFO *cs;
234
505
  init_available_charsets(MYF(0));
235
506
 
236
507
  cs=all_charsets[charset_number];
237
508
  if (cs && (cs->number == charset_number) && cs->name )
238
509
    return (char*) cs->name;
239
 
 
 
510
  
240
511
  return (char*) "?";   /* this mimics find_type() */
241
512
}
242
513
 
243
514
 
244
 
static const CHARSET_INFO *get_internal_charset(uint32_t cs_number)
 
515
static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
245
516
{
 
517
  char  buf[FN_REFLEN];
246
518
  CHARSET_INFO *cs;
247
519
  /*
248
520
    To make things thread safe we are not allowing other threads to interfere
253
525
  {
254
526
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
255
527
    {
256
 
      assert(0);
 
528
      strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
 
529
      my_read_charset_file(buf,flags);
257
530
    }
258
531
    cs= (cs->state & MY_CS_AVAILABLE) ? cs : NULL;
259
532
  }
270
543
}
271
544
 
272
545
 
273
 
const CHARSET_INFO *get_charset(uint32_t cs_number, myf flags)
 
546
CHARSET_INFO *get_charset(uint cs_number, myf flags)
274
547
{
275
 
  const CHARSET_INFO *cs;
 
548
  CHARSET_INFO *cs;
276
549
  if (cs_number == default_charset_info->number)
277
550
    return default_charset_info;
278
551
 
279
552
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
280
 
 
 
553
  
281
554
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
282
555
    return NULL;
283
 
 
284
 
  cs= get_internal_charset(cs_number);
 
556
  
 
557
  cs=get_internal_charset(cs_number, flags);
285
558
 
286
559
  if (!cs && (flags & MY_WME))
287
560
  {
288
561
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
289
 
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
562
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
290
563
    cs_string[0]='#';
291
564
    int10_to_str(cs_number, cs_string+1, 10);
292
565
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
294
567
  return cs;
295
568
}
296
569
 
297
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
 
570
CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
298
571
{
299
 
  uint32_t cs_number;
300
 
  const CHARSET_INFO *cs;
 
572
  uint cs_number;
 
573
  CHARSET_INFO *cs;
301
574
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
302
575
 
303
576
  cs_number=get_collation_number(cs_name);
304
 
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
 
577
  cs= cs_number ? get_internal_charset(cs_number,flags) : NULL;
305
578
 
306
579
  if (!cs && (flags & MY_WME))
307
580
  {
308
581
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
309
 
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
582
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
310
583
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
311
584
  }
312
585
 
314
587
}
315
588
 
316
589
 
317
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
318
 
                                    uint32_t cs_flags,
 
590
CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
591
                                    uint cs_flags,
319
592
                                    myf flags)
320
593
{
321
 
  uint32_t cs_number;
322
 
  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));
323
598
 
324
599
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
325
600
 
326
601
  cs_number= get_charset_number(cs_name, cs_flags);
327
 
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
 
602
  cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
328
603
 
329
604
  if (!cs && (flags & MY_WME))
330
605
  {
331
606
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
332
 
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
607
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
333
608
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
334
609
  }
335
610
 
336
 
  return(cs);
 
611
  DBUG_RETURN(cs);
337
612
}
338
613
 
339
614
 
342
617
 
343
618
  The function tries to resolve character set by the specified name. If
344
619
  there is character set with the given name, it is assigned to the "cs"
345
 
  parameter and false is returned. If there is no such character set,
346
 
  "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.
347
622
 
348
623
  @param[in] cs_name    Character set name.
349
624
  @param[in] default_cs Default character set.
350
625
  @param[out] cs        Variable to store character set.
351
626
 
352
 
  @return false if character set was resolved successfully; true if there
 
627
  @return FALSE if character set was resolved successfully; TRUE if there
353
628
  is no character set with given name.
354
629
*/
355
630
 
356
 
bool resolve_charset(const char *cs_name,
357
 
                     const CHARSET_INFO *default_cs,
358
 
                     const CHARSET_INFO **cs)
 
631
my_bool resolve_charset(const char *cs_name,
 
632
                        CHARSET_INFO *default_cs,
 
633
                        CHARSET_INFO **cs)
359
634
{
360
635
  *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
361
636
 
362
637
  if (*cs == NULL)
363
638
  {
364
639
    *cs= default_cs;
365
 
    return true;
 
640
    return TRUE;
366
641
  }
367
642
 
368
 
  return false;
 
643
  return FALSE;
369
644
}
370
645
 
371
646
 
374
649
 
375
650
  The function tries to resolve collation by the specified name. If there
376
651
  is collation with the given name, it is assigned to the "cl" parameter
377
 
  and false is returned. If there is no such collation, "default_cl" is
378
 
  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.
379
654
 
380
655
  @param[out] cl        Variable to store collation.
381
656
  @param[in] cl_name    Collation name.
382
657
  @param[in] default_cl Default collation.
383
658
 
384
 
  @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
385
660
  collation with given name.
386
661
*/
387
662
 
388
 
bool resolve_collation(const char *cl_name,
389
 
                       const CHARSET_INFO *default_cl,
390
 
                       const CHARSET_INFO **cl)
 
663
my_bool resolve_collation(const char *cl_name,
 
664
                          CHARSET_INFO *default_cl,
 
665
                          CHARSET_INFO **cl)
391
666
{
392
667
  *cl= get_charset_by_name(cl_name, MYF(0));
393
668
 
394
669
  if (*cl == NULL)
395
670
  {
396
671
    *cl= default_cl;
397
 
    return true;
398
 
  }
399
 
 
400
 
  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);
401
791
}
402
792
 
403
793
 
430
820
  Escape apostrophes by doubling them up
431
821
 
432
822
  SYNOPSIS
433
 
    escape_quotes_for_drizzle()
 
823
    escape_quotes_for_mysql()
434
824
    charset_info        Charset of the strings
435
825
    to                  Buffer for escaped string
436
826
    to_length           Length of destination buffer, or 0
447
837
    mean "big enough"
448
838
 
449
839
  RETURN VALUES
450
 
    UINT32_MAX  The escaped string did not fit in the to buffer
 
840
    ~0          The escaped string did not fit in the to buffer
451
841
    >=0         The length of the escaped string
452
842
*/
453
843
 
454
 
size_t escape_quotes_for_drizzle(const CHARSET_INFO *charset_info,
455
 
                                 char *to, size_t to_length,
456
 
                                 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)
457
847
{
458
848
  const char *to_start= to;
459
849
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
460
 
  bool overflow= false;
 
850
  my_bool overflow= FALSE;
461
851
#ifdef USE_MB
462
 
  bool use_mb_flag= use_mb(charset_info);
 
852
  my_bool use_mb_flag= use_mb(charset_info);
463
853
#endif
464
854
  for (end= from + length; from < end; from++)
465
855
  {
469
859
    {
470
860
      if (to + tmp_length > to_end)
471
861
      {
472
 
        overflow= true;
 
862
        overflow= TRUE;
473
863
        break;
474
864
      }
475
865
      while (tmp_length--)
487
877
    {
488
878
      if (to + 2 > to_end)
489
879
      {
490
 
        overflow= true;
 
880
        overflow= TRUE;
491
881
        break;
492
882
      }
493
883
      *to++= '\'';
497
887
    {
498
888
      if (to + 1 > to_end)
499
889
      {
500
 
        overflow= true;
 
890
        overflow= TRUE;
501
891
        break;
502
892
      }
503
893
      *to++= *from;
504
894
    }
505
895
  }
506
896
  *to= 0;
507
 
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
 
897
  return overflow ? (ulong)~0 : (ulong) (to - to_start);
508
898
}