~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.cc

  • Committer: Monty Taylor
  • Date: 2008-11-16 06:29:53 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116062953-ivdltjmfe009b5fr
Moved stuff into item/

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
 
34
22
 
35
23
/*
36
24
  The code below implements this functionality:
37
 
 
 
25
  
38
26
    - Initializing charset related structures
39
27
    - Loading dynamic charsets
40
 
    - Searching for a proper CHARSET_INFO
 
28
    - Searching for a proper CHARSET_INFO 
41
29
      using charset name, collation name or collation ID
42
30
    - Setting server default character set
43
31
*/
56
44
       cs < all_charsets+array_elements(all_charsets)-1 ;
57
45
       cs++)
58
46
  {
59
 
    if ( cs[0] && cs[0]->name &&
 
47
    if ( cs[0] && cs[0]->name && 
60
48
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
61
49
      return cs[0]->number;
62
 
  }
 
50
  }  
63
51
  return 0;
64
52
}
65
53
 
70
58
  unsigned char *state_map;
71
59
  unsigned char *ident_map;
72
60
 
73
 
  if (!(cs->state_map= (unsigned char*) cs_alloc(256)))
 
61
  if (!(cs->state_map= (unsigned char*) my_once_alloc(256, MYF(MY_WME))))
74
62
    return 1;
75
63
    
76
 
  if (!(cs->ident_map= (unsigned char*) cs_alloc(256)))
 
64
  if (!(cs->ident_map= (unsigned char*) my_once_alloc(256, MYF(MY_WME))))
77
65
    return 1;
78
66
 
79
67
  state_map= cs->state_map;
80
68
  ident_map= cs->ident_map;
81
 
 
 
69
  
82
70
  /* Fill state_map with states to get a faster parser */
83
71
  for (i=0; i < 256 ; i++)
84
72
  {
86
74
      state_map[i]=(unsigned char) MY_LEX_IDENT;
87
75
    else if (my_isdigit(cs,i))
88
76
      state_map[i]=(unsigned char) MY_LEX_NUMBER_IDENT;
 
77
#if defined(USE_MB) && defined(USE_MB_IDENT)
89
78
    else if (my_mbcharlen(cs, i)>1)
90
79
      state_map[i]=(unsigned char) MY_LEX_IDENT;
 
80
#endif
91
81
    else if (my_isspace(cs,i))
92
82
      state_map[i]=(unsigned char) MY_LEX_SKIP;
93
83
    else
126
116
}
127
117
 
128
118
 
129
 
static bool charset_initialized= false;
 
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
}
130
144
 
131
145
CHARSET_INFO *all_charsets[256];
132
146
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
137
151
  cs->state|= MY_CS_AVAILABLE;
138
152
}
139
153
 
140
 
void *cs_alloc(size_t size)
 
154
static void *cs_alloc(size_t size)
141
155
{
142
 
  void *ptr= malloc(size);
143
 
 
144
 
  memory_vector.push_back(ptr);
145
 
 
146
 
  return ptr;
 
156
  return my_once_alloc(size, MYF(MY_WME));
147
157
}
148
158
 
149
159
 
150
 
 
151
160
static bool init_available_charsets(myf myflags)
152
161
{
153
 
  bool error= false;
 
162
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
163
  bool error=false;
154
164
  /*
155
165
    We have to use charset_initialized to not lock on THR_LOCK_charset
156
166
    inside get_internal_charset...
157
167
  */
158
 
  if (charset_initialized == false)
 
168
  if (!charset_initialized)
159
169
  {
160
170
    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++)
 
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)
168
177
    {
169
 
      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++)
170
185
      {
171
 
        if (cs[0]->ctype)
172
 
          if (init_state_maps(*cs))
173
 
            *cs= NULL;
 
186
        if (*cs)
 
187
        {
 
188
          if (cs[0]->ctype)
 
189
            if (init_state_maps(*cs))
 
190
              *cs= NULL;
 
191
        }
174
192
      }
 
193
      
 
194
      my_stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
195
      charset_initialized=1;
175
196
    }
176
 
 
177
 
    charset_initialized= true;
 
197
    pthread_mutex_unlock(&THR_LOCK_charset);
178
198
  }
179
 
  assert(charset_initialized);
180
 
 
181
199
  return error;
182
200
}
183
201
 
184
202
 
185
203
void free_charsets(void)
186
204
{
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
 
 
 
205
  charset_initialized=0;
197
206
}
198
207
 
199
208
 
208
217
{
209
218
  CHARSET_INFO **cs;
210
219
  init_available_charsets(MYF(0));
211
 
 
 
220
  
212
221
  for (cs= all_charsets;
213
222
       cs < all_charsets+array_elements(all_charsets)-1 ;
214
223
       cs++)
216
225
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
217
226
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
218
227
      return cs[0]->number;
219
 
  }
 
228
  }  
220
229
  return 0;
221
230
}
222
231
 
229
238
  cs=all_charsets[charset_number];
230
239
  if (cs && (cs->number == charset_number) && cs->name )
231
240
    return (char*) cs->name;
232
 
 
 
241
  
233
242
  return (char*) "?";   /* this mimics find_type() */
234
243
}
235
244
 
241
250
    To make things thread safe we are not allowing other threads to interfere
242
251
    while we may changing the cs_info_table
243
252
  */
 
253
  pthread_mutex_lock(&THR_LOCK_charset);
244
254
  if ((cs= all_charsets[cs_number]))
245
255
  {
246
256
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
257
267
    else
258
268
      cs->state|= MY_CS_READY;
259
269
  }
260
 
 
 
270
  pthread_mutex_unlock(&THR_LOCK_charset);
261
271
  return cs;
262
272
}
263
273
 
264
274
 
265
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
275
const CHARSET_INFO *get_charset(uint32_t cs_number, myf flags)
266
276
{
267
277
  const CHARSET_INFO *cs;
268
278
  if (cs_number == default_charset_info->number)
269
279
    return default_charset_info;
270
280
 
271
281
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
272
 
 
 
282
  
273
283
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
274
284
    return NULL;
275
 
 
 
285
  
276
286
  cs= get_internal_charset(cs_number);
277
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
  }
278
296
  return cs;
279
297
}
280
298
 
281
 
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)
282
300
{
283
301
  uint32_t cs_number;
284
302
  const CHARSET_INFO *cs;
285
303
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
286
304
 
287
 
  cs_number= get_collation_number(cs_name);
 
305
  cs_number=get_collation_number(cs_name);
288
306
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
289
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
 
290
315
  return cs;
291
316
}
292
317
 
293
318
 
294
 
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)
295
322
{
296
323
  uint32_t cs_number;
297
324
  const CHARSET_INFO *cs;
301
328
  cs_number= get_charset_number(cs_name, cs_flags);
302
329
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
303
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
 
304
338
  return(cs);
305
339
}
306
340
 
307
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
 
308
431
/*
309
432
  Escape apostrophes by doubling them up
310
433
 
337
460
  const char *to_start= to;
338
461
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
339
462
  bool overflow= false;
 
463
#ifdef USE_MB
340
464
  bool use_mb_flag= use_mb(charset_info);
 
465
#endif
341
466
  for (end= from + length; from < end; from++)
342
467
  {
 
468
#ifdef USE_MB
343
469
    int tmp_length;
344
470
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
345
471
    {
358
484
      turned into a multi-byte character by the addition of an escaping
359
485
      character, because we are only escaping the ' character with itself.
360
486
     */
 
487
#endif
361
488
    if (*from == '\'')
362
489
    {
363
490
      if (to + 2 > to_end)
381
508
  *to= 0;
382
509
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
383
510
}
384
 
 
385
 
} /* namespace drizzled */