~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Monty Taylor
  • Date: 2008-08-05 19:01:20 UTC
  • mto: (266.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 266.
  • Revision ID: monty@inaugust.com-20080805190120-tsuziqz2mfqcw7pe
Removed libmysyslt.la, made mysys a noinst_ and made everything use it. It's
not a standalone lib, there's no reason to pretend otherwise.

Show diffs side-by-side

added added

removed removed

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