~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Brian Aker
  • Date: 2008-10-18 15:43:20 UTC
  • mto: (492.3.20 drizzle-clean-code)
  • mto: This revision was merged to the branch mainline in revision 530.
  • Revision ID: brian@tangent.org-20081018154320-jc9jyij3mdf08abp
Updating tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
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
 
#include <drizzled/visibility.h>
26
 
 
27
 
using namespace std;
28
 
 
29
 
namespace drizzled
30
 
{
31
 
 
32
 
/*
33
 
  We collect memory in this vector that we free on delete.
34
 
*/
35
 
static vector<unsigned char*> memory_vector;
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "mysys_priv.h"
 
17
#include "mysys_err.h"
 
18
#include <mystrings/m_ctype.h>
 
19
#include <mystrings/m_string.h>
 
20
#include <my_dir.h>
 
21
 
36
22
 
37
23
/*
38
24
  The code below implements this functionality:
39
 
 
 
25
  
40
26
    - Initializing charset related structures
41
27
    - Loading dynamic charsets
42
 
    - Searching for a proper CHARSET_INFO
 
28
    - Searching for a proper CHARSET_INFO 
43
29
      using charset name, collation name or collation ID
44
30
    - Setting server default character set
45
31
*/
53
39
static uint
54
40
get_collation_number_internal(const char *name)
55
41
{
56
 
  for (CHARSET_INFO **cs= all_charsets;
57
 
       cs < all_charsets+array_elements(all_charsets)-1;
 
42
  CHARSET_INFO **cs;
 
43
  for (cs= all_charsets;
 
44
       cs < all_charsets+array_elements(all_charsets)-1 ;
58
45
       cs++)
59
46
  {
60
 
    if ( cs[0] && cs[0]->name && !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
61
 
    {
 
47
    if ( cs[0] && cs[0]->name && 
 
48
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
62
49
      return cs[0]->number;
63
 
    }
64
 
  }
 
50
  }  
65
51
  return 0;
66
52
}
67
53
 
68
 
static unsigned char *cs_alloc(size_t size)
69
 
{
70
 
  memory_vector.push_back(new unsigned char[size]);
71
 
  return memory_vector.back();
72
 
}
73
54
 
74
55
static bool init_state_maps(CHARSET_INFO *cs)
75
56
{
76
 
  if (!(cs->state_map= cs_alloc(256)))
 
57
  uint32_t i;
 
58
  unsigned char *state_map;
 
59
  unsigned char *ident_map;
 
60
 
 
61
  if (!(cs->state_map= (unsigned char*) my_once_alloc(256, MYF(MY_WME))))
77
62
    return 1;
78
63
    
79
 
  if (!(cs->ident_map= cs_alloc(256)))
 
64
  if (!(cs->ident_map= (unsigned char*) my_once_alloc(256, MYF(MY_WME))))
80
65
    return 1;
81
66
 
82
 
  unsigned char *state_map= cs->state_map;
83
 
  unsigned char *ident_map= cs->ident_map;
84
 
 
 
67
  state_map= cs->state_map;
 
68
  ident_map= cs->ident_map;
 
69
  
85
70
  /* Fill state_map with states to get a faster parser */
86
 
  for (int i= 0; i < 256; i++)
 
71
  for (i=0; i < 256 ; i++)
87
72
  {
88
73
    if (my_isalpha(cs,i))
89
 
      state_map[i]= MY_LEX_IDENT;
 
74
      state_map[i]=(unsigned char) MY_LEX_IDENT;
90
75
    else if (my_isdigit(cs,i))
91
 
      state_map[i]= MY_LEX_NUMBER_IDENT;
 
76
      state_map[i]=(unsigned char) MY_LEX_NUMBER_IDENT;
 
77
#if defined(USE_MB) && defined(USE_MB_IDENT)
92
78
    else if (my_mbcharlen(cs, i)>1)
93
 
      state_map[i]= MY_LEX_IDENT;
 
79
      state_map[i]=(unsigned char) MY_LEX_IDENT;
 
80
#endif
94
81
    else if (my_isspace(cs,i))
95
 
      state_map[i]= MY_LEX_SKIP;
 
82
      state_map[i]=(unsigned char) MY_LEX_SKIP;
96
83
    else
97
 
      state_map[i]= MY_LEX_CHAR;
 
84
      state_map[i]=(unsigned char) MY_LEX_CHAR;
98
85
  }
99
 
  state_map['_']=state_map['$']= MY_LEX_IDENT;
100
 
  state_map['\'']= MY_LEX_STRING;
101
 
  state_map['.']= MY_LEX_REAL_OR_POINT;
102
 
  state_map['>']=state_map['=']=state_map['!']=  MY_LEX_CMP_OP;
103
 
  state_map['<']=  MY_LEX_LONG_CMP_OP;
104
 
  state_map['&']=state_map['|']= MY_LEX_BOOL;
105
 
  state_map['#']= MY_LEX_COMMENT;
106
 
  state_map[';']= MY_LEX_SEMICOLON;
107
 
  state_map[':']= MY_LEX_SET_VAR;
108
 
  state_map[0]= MY_LEX_EOL;
109
 
  state_map['\\']=  MY_LEX_ESCAPE;
110
 
  state_map['/']=  MY_LEX_LONG_COMMENT;
111
 
  state_map['*']=  MY_LEX_END_LONG_COMMENT;
112
 
  state_map['@']=  MY_LEX_USER_END;
113
 
  state_map['`']=  MY_LEX_USER_VARIABLE_DELIMITER;
114
 
  state_map['"']=  MY_LEX_STRING_OR_DELIMITER;
 
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;
115
102
 
116
103
  /*
117
104
    Create a second map to make it faster to find identifiers
118
105
  */
119
 
  for (int i= 0; i < 256; i++)
 
106
  for (i=0; i < 256 ; i++)
120
107
  {
121
 
    ident_map[i]= state_map[i] == MY_LEX_IDENT || state_map[i] == MY_LEX_NUMBER_IDENT;
 
108
    ident_map[i]= (unsigned char) (state_map[i] == MY_LEX_IDENT ||
 
109
                           state_map[i] == MY_LEX_NUMBER_IDENT);
122
110
  }
123
111
 
124
112
  /* Special handling of hex and binary strings */
125
 
  state_map['x']= state_map['X']=  MY_LEX_IDENT_OR_HEX;
126
 
  state_map['b']= state_map['B']=  MY_LEX_IDENT_OR_BIN;
 
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;
127
115
  return 0;
128
116
}
129
117
 
130
 
static bool charset_initialized= false;
131
 
 
132
 
DRIZZLED_API CHARSET_INFO *all_charsets[256];
133
 
const DRIZZLED_API CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
 
118
 
 
119
#define MY_CHARSET_INDEX "Index.xml"
 
120
 
 
121
const char *charsets_dir= NULL;
 
122
static int charset_initialized=0;
 
123
 
 
124
 
 
125
char *get_charsets_dir(char *buf)
 
126
{
 
127
  const char *sharedir= SHAREDIR;
 
128
  char *res;
 
129
 
 
130
  if (charsets_dir != NULL)
 
131
    strmake(buf, charsets_dir, FN_REFLEN-1);
 
132
  else
 
133
  {
 
134
    if (test_if_hard_path(sharedir) ||
 
135
        is_prefix(sharedir, DEFAULT_CHARSET_HOME))
 
136
      strxmov(buf, sharedir, "/", CHARSET_DIR, NULL);
 
137
    else
 
138
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
 
139
              NULL);
 
140
  }
 
141
  res= convert_dirname(buf,buf,NULL);
 
142
  return(res);
 
143
}
 
144
 
 
145
CHARSET_INFO *all_charsets[256];
 
146
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
134
147
 
135
148
void add_compiled_collation(CHARSET_INFO * cs)
136
149
{
138
151
  cs->state|= MY_CS_AVAILABLE;
139
152
}
140
153
 
 
154
static void *cs_alloc(size_t size)
 
155
{
 
156
  return my_once_alloc(size, MYF(MY_WME));
 
157
}
 
158
 
 
159
 
141
160
static bool init_available_charsets(myf myflags)
142
161
{
143
 
  bool error= false;
 
162
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
163
  bool error=false;
144
164
  /*
145
165
    We have to use charset_initialized to not lock on THR_LOCK_charset
146
166
    inside get_internal_charset...
147
167
  */
148
 
  if (charset_initialized == false)
 
168
  if (!charset_initialized)
149
169
  {
150
170
    CHARSET_INFO **cs;
151
 
    memset(&all_charsets, 0, sizeof(all_charsets));
152
 
    init_compiled_charsets(myflags);
153
 
 
154
 
    /* Copy compiled charsets */
155
 
    for (cs=all_charsets;
156
 
         cs < all_charsets+array_elements(all_charsets)-1 ;
157
 
         cs++)
 
171
    /*
 
172
      To make things thread safe we are not allowing other threads to interfere
 
173
      while we may changing the cs_info_table
 
174
    */
 
175
    pthread_mutex_lock(&THR_LOCK_charset);
 
176
    if (!charset_initialized)
158
177
    {
159
 
      if (*cs)
 
178
      memset(&all_charsets, 0, sizeof(all_charsets));
 
179
      init_compiled_charsets(myflags);
 
180
      
 
181
      /* Copy compiled charsets */
 
182
      for (cs=all_charsets;
 
183
           cs < all_charsets+array_elements(all_charsets)-1 ;
 
184
           cs++)
160
185
      {
161
 
        if (cs[0]->ctype)
162
 
          if (init_state_maps(*cs))
163
 
            *cs= NULL;
 
186
        if (*cs)
 
187
        {
 
188
          if (cs[0]->ctype)
 
189
            if (init_state_maps(*cs))
 
190
              *cs= NULL;
 
191
        }
164
192
      }
 
193
      
 
194
      my_stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
195
      charset_initialized=1;
165
196
    }
166
 
 
167
 
    charset_initialized= true;
 
197
    pthread_mutex_unlock(&THR_LOCK_charset);
168
198
  }
169
 
  assert(charset_initialized);
170
 
 
171
199
  return error;
172
200
}
173
201
 
174
202
 
175
 
void free_charsets()
 
203
void free_charsets(void)
176
204
{
177
 
  charset_initialized= false;
178
 
 
179
 
  while (not memory_vector.empty())
180
 
  {
181
 
    delete[] memory_vector.back();
182
 
    memory_vector.pop_back();
183
 
  }
 
205
  charset_initialized=0;
184
206
}
185
207
 
186
208
 
195
217
{
196
218
  CHARSET_INFO **cs;
197
219
  init_available_charsets(MYF(0));
198
 
 
 
220
  
199
221
  for (cs= all_charsets;
200
222
       cs < all_charsets+array_elements(all_charsets)-1 ;
201
223
       cs++)
202
224
  {
203
 
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) && !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
 
225
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
 
226
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
204
227
      return cs[0]->number;
205
 
  }
 
228
  }  
206
229
  return 0;
207
230
}
208
231
 
209
232
 
210
233
const char *get_charset_name(uint32_t charset_number)
211
234
{
 
235
  const CHARSET_INFO *cs;
212
236
  init_available_charsets(MYF(0));
213
237
 
214
 
  const CHARSET_INFO *cs= all_charsets[charset_number];
 
238
  cs=all_charsets[charset_number];
215
239
  if (cs && (cs->number == charset_number) && cs->name )
216
 
    return cs->name;
217
 
 
218
 
  return "?";   /* this mimics find_type() */
 
240
    return (char*) cs->name;
 
241
  
 
242
  return (char*) "?";   /* this mimics find_type() */
219
243
}
220
244
 
221
245
 
226
250
    To make things thread safe we are not allowing other threads to interfere
227
251
    while we may changing the cs_info_table
228
252
  */
 
253
  pthread_mutex_lock(&THR_LOCK_charset);
229
254
  if ((cs= all_charsets[cs_number]))
230
255
  {
231
256
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
242
267
    else
243
268
      cs->state|= MY_CS_READY;
244
269
  }
245
 
 
 
270
  pthread_mutex_unlock(&THR_LOCK_charset);
246
271
  return cs;
247
272
}
248
273
 
249
274
 
250
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
275
const const CHARSET_INFO *get_charset(uint32_t cs_number, myf flags)
251
276
{
252
277
  const CHARSET_INFO *cs;
253
278
  if (cs_number == default_charset_info->number)
254
279
    return default_charset_info;
255
280
 
256
281
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
257
 
 
 
282
  
258
283
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
259
284
    return NULL;
260
 
 
 
285
  
261
286
  cs= get_internal_charset(cs_number);
262
287
 
 
288
  if (!cs && (flags & MY_WME))
 
289
  {
 
290
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
 
291
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
292
    cs_string[0]='#';
 
293
    int10_to_str(cs_number, cs_string+1, 10);
 
294
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
 
295
  }
263
296
  return cs;
264
297
}
265
298
 
266
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
 
299
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
267
300
{
268
301
  uint32_t cs_number;
269
302
  const CHARSET_INFO *cs;
270
303
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
271
304
 
272
 
  cs_number= get_collation_number(cs_name);
 
305
  cs_number=get_collation_number(cs_name);
273
306
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
274
307
 
 
308
  if (!cs && (flags & MY_WME))
 
309
  {
 
310
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
311
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
312
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
 
313
  }
 
314
 
275
315
  return cs;
276
316
}
277
317
 
278
318
 
279
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
 
319
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
320
                                    uint32_t cs_flags,
 
321
                                    myf flags)
280
322
{
281
323
  uint32_t cs_number;
282
324
  const CHARSET_INFO *cs;
286
328
  cs_number= get_charset_number(cs_name, cs_flags);
287
329
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
288
330
 
 
331
  if (!cs && (flags & MY_WME))
 
332
  {
 
333
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
334
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
335
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
 
336
  }
 
337
 
289
338
  return(cs);
290
339
}
291
340
 
292
341
 
 
342
/**
 
343
  Resolve character set by the character set name (utf8, latin1, ...).
 
344
 
 
345
  The function tries to resolve character set by the specified name. If
 
346
  there is character set with the given name, it is assigned to the "cs"
 
347
  parameter and false is returned. If there is no such character set,
 
348
  "default_cs" is assigned to the "cs" and true is returned.
 
349
 
 
350
  @param[in] cs_name    Character set name.
 
351
  @param[in] default_cs Default character set.
 
352
  @param[out] cs        Variable to store character set.
 
353
 
 
354
  @return false if character set was resolved successfully; true if there
 
355
  is no character set with given name.
 
356
*/
 
357
 
 
358
bool resolve_charset(const char *cs_name,
 
359
                     const CHARSET_INFO *default_cs,
 
360
                     const CHARSET_INFO **cs)
 
361
{
 
362
  *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
 
363
 
 
364
  if (*cs == NULL)
 
365
  {
 
366
    *cs= default_cs;
 
367
    return true;
 
368
  }
 
369
 
 
370
  return false;
 
371
}
 
372
 
 
373
 
 
374
/**
 
375
  Resolve collation by the collation name (utf8_general_ci, ...).
 
376
 
 
377
  The function tries to resolve collation by the specified name. If there
 
378
  is collation with the given name, it is assigned to the "cl" parameter
 
379
  and false is returned. If there is no such collation, "default_cl" is
 
380
  assigned to the "cl" and true is returned.
 
381
 
 
382
  @param[out] cl        Variable to store collation.
 
383
  @param[in] cl_name    Collation name.
 
384
  @param[in] default_cl Default collation.
 
385
 
 
386
  @return false if collation was resolved successfully; true if there is no
 
387
  collation with given name.
 
388
*/
 
389
 
 
390
bool resolve_collation(const char *cl_name,
 
391
                       const CHARSET_INFO *default_cl,
 
392
                       const CHARSET_INFO **cl)
 
393
{
 
394
  *cl= get_charset_by_name(cl_name, MYF(0));
 
395
 
 
396
  if (*cl == NULL)
 
397
  {
 
398
    *cl= default_cl;
 
399
    return true;
 
400
  }
 
401
 
 
402
  return false;
 
403
}
 
404
 
 
405
 
 
406
#ifdef BACKSLASH_MBTAIL
 
407
static CHARSET_INFO *fs_cset_cache= NULL;
 
408
 
 
409
CHARSET_INFO *fs_character_set()
 
410
{
 
411
  if (!fs_cset_cache)
 
412
  {
 
413
    char buf[10]= "cp";
 
414
    GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
 
415
                  buf+2, sizeof(buf)-3);
 
416
    /*
 
417
      We cannot call get_charset_by_name here
 
418
      because fs_character_set() is executed before
 
419
      LOCK_THD_charset mutex initialization, which
 
420
      is used inside get_charset_by_name.
 
421
      As we're now interested in cp932 only,
 
422
      let's just detect it using strcmp().
 
423
    */
 
424
    fs_cset_cache= !strcmp(buf, "cp932") ?
 
425
                   &my_charset_cp932_japanese_ci : &my_charset_bin;
 
426
  }
 
427
  return fs_cset_cache;
 
428
}
 
429
#endif
 
430
 
293
431
/*
294
432
  Escape apostrophes by doubling them up
295
433
 
322
460
  const char *to_start= to;
323
461
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
324
462
  bool overflow= false;
 
463
#ifdef USE_MB
325
464
  bool use_mb_flag= use_mb(charset_info);
 
465
#endif
326
466
  for (end= from + length; from < end; from++)
327
467
  {
 
468
#ifdef USE_MB
328
469
    int tmp_length;
329
470
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
330
471
    {
343
484
      turned into a multi-byte character by the addition of an escaping
344
485
      character, because we are only escaping the ' character with itself.
345
486
     */
 
487
#endif
346
488
    if (*from == '\'')
347
489
    {
348
490
      if (to + 2 > to_end)
364
506
    }
365
507
  }
366
508
  *to= 0;
367
 
  return overflow ? UINT32_MAX : to - to_start;
 
509
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
368
510
}
369
 
 
370
 
} /* namespace drizzled */