~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Brian Aker
  • Date: 2008-10-11 21:01:52 UTC
  • Revision ID: brian@tangent.org-20081011210152-8ipnqumvhtt1zcmj
Added back more 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
 
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;
 
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
 
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_MAX_ALLOWED_BUF 1024*1024
 
120
#define MY_CHARSET_INDEX "Index.xml"
 
121
 
 
122
const char *charsets_dir= NULL;
 
123
static int charset_initialized=0;
 
124
 
 
125
 
 
126
char *get_charsets_dir(char *buf)
 
127
{
 
128
  const char *sharedir= SHAREDIR;
 
129
  char *res;
 
130
 
 
131
  if (charsets_dir != NULL)
 
132
    strmake(buf, charsets_dir, FN_REFLEN-1);
 
133
  else
 
134
  {
 
135
    if (test_if_hard_path(sharedir) ||
 
136
        is_prefix(sharedir, DEFAULT_CHARSET_HOME))
 
137
      strxmov(buf, sharedir, "/", CHARSET_DIR, NULL);
 
138
    else
 
139
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
 
140
              NULL);
 
141
  }
 
142
  res= convert_dirname(buf,buf,NULL);
 
143
  return(res);
 
144
}
130
145
 
131
146
CHARSET_INFO *all_charsets[256];
132
147
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
137
152
  cs->state|= MY_CS_AVAILABLE;
138
153
}
139
154
 
140
 
void *cs_alloc(size_t size)
 
155
static void *cs_alloc(size_t size)
141
156
{
142
 
  void *ptr= malloc(size);
143
 
 
144
 
  memory_vector.push_back(ptr);
145
 
 
146
 
  return ptr;
 
157
  return my_once_alloc(size, MYF(MY_WME));
147
158
}
148
159
 
149
160
 
150
 
 
151
161
static bool init_available_charsets(myf myflags)
152
162
{
153
 
  bool error= false;
 
163
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
164
  bool error=false;
154
165
  /*
155
166
    We have to use charset_initialized to not lock on THR_LOCK_charset
156
167
    inside get_internal_charset...
157
168
  */
158
 
  if (charset_initialized == false)
 
169
  if (!charset_initialized)
159
170
  {
160
171
    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++)
 
172
    /*
 
173
      To make things thread safe we are not allowing other threads to interfere
 
174
      while we may changing the cs_info_table
 
175
    */
 
176
    pthread_mutex_lock(&THR_LOCK_charset);
 
177
    if (!charset_initialized)
168
178
    {
169
 
      if (*cs)
 
179
      memset(&all_charsets, 0, sizeof(all_charsets));
 
180
      init_compiled_charsets(myflags);
 
181
      
 
182
      /* Copy compiled charsets */
 
183
      for (cs=all_charsets;
 
184
           cs < all_charsets+array_elements(all_charsets)-1 ;
 
185
           cs++)
170
186
      {
171
 
        if (cs[0]->ctype)
172
 
          if (init_state_maps(*cs))
173
 
            *cs= NULL;
 
187
        if (*cs)
 
188
        {
 
189
          if (cs[0]->ctype)
 
190
            if (init_state_maps(*cs))
 
191
              *cs= NULL;
 
192
        }
174
193
      }
 
194
      
 
195
      my_stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
196
      charset_initialized=1;
175
197
    }
176
 
 
177
 
    charset_initialized= true;
 
198
    pthread_mutex_unlock(&THR_LOCK_charset);
178
199
  }
179
 
  assert(charset_initialized);
180
 
 
181
200
  return error;
182
201
}
183
202
 
184
203
 
185
204
void free_charsets(void)
186
205
{
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
 
 
 
206
  charset_initialized=0;
197
207
}
198
208
 
199
209
 
208
218
{
209
219
  CHARSET_INFO **cs;
210
220
  init_available_charsets(MYF(0));
211
 
 
 
221
  
212
222
  for (cs= all_charsets;
213
223
       cs < all_charsets+array_elements(all_charsets)-1 ;
214
224
       cs++)
216
226
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
217
227
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
218
228
      return cs[0]->number;
219
 
  }
 
229
  }  
220
230
  return 0;
221
231
}
222
232
 
229
239
  cs=all_charsets[charset_number];
230
240
  if (cs && (cs->number == charset_number) && cs->name )
231
241
    return (char*) cs->name;
232
 
 
 
242
  
233
243
  return (char*) "?";   /* this mimics find_type() */
234
244
}
235
245
 
241
251
    To make things thread safe we are not allowing other threads to interfere
242
252
    while we may changing the cs_info_table
243
253
  */
 
254
  pthread_mutex_lock(&THR_LOCK_charset);
244
255
  if ((cs= all_charsets[cs_number]))
245
256
  {
246
257
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
257
268
    else
258
269
      cs->state|= MY_CS_READY;
259
270
  }
260
 
 
 
271
  pthread_mutex_unlock(&THR_LOCK_charset);
261
272
  return cs;
262
273
}
263
274
 
264
275
 
265
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
276
const const CHARSET_INFO *get_charset(uint32_t cs_number, myf flags)
266
277
{
267
278
  const CHARSET_INFO *cs;
268
279
  if (cs_number == default_charset_info->number)
269
280
    return default_charset_info;
270
281
 
271
282
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
272
 
 
 
283
  
273
284
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
274
285
    return NULL;
275
 
 
 
286
  
276
287
  cs= get_internal_charset(cs_number);
277
288
 
 
289
  if (!cs && (flags & MY_WME))
 
290
  {
 
291
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
 
292
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
293
    cs_string[0]='#';
 
294
    int10_to_str(cs_number, cs_string+1, 10);
 
295
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
 
296
  }
278
297
  return cs;
279
298
}
280
299
 
281
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
 
300
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
282
301
{
283
302
  uint32_t cs_number;
284
303
  const CHARSET_INFO *cs;
285
304
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
286
305
 
287
 
  cs_number= get_collation_number(cs_name);
 
306
  cs_number=get_collation_number(cs_name);
288
307
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
289
308
 
 
309
  if (!cs && (flags & MY_WME))
 
310
  {
 
311
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
312
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
313
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
 
314
  }
 
315
 
290
316
  return cs;
291
317
}
292
318
 
293
319
 
294
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
 
320
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
321
                                    uint32_t cs_flags,
 
322
                                    myf flags)
295
323
{
296
324
  uint32_t cs_number;
297
325
  const CHARSET_INFO *cs;
301
329
  cs_number= get_charset_number(cs_name, cs_flags);
302
330
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
303
331
 
 
332
  if (!cs && (flags & MY_WME))
 
333
  {
 
334
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
335
    my_stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
336
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
 
337
  }
 
338
 
304
339
  return(cs);
305
340
}
306
341
 
307
342
 
 
343
/**
 
344
  Resolve character set by the character set name (utf8, latin1, ...).
 
345
 
 
346
  The function tries to resolve character set by the specified name. If
 
347
  there is character set with the given name, it is assigned to the "cs"
 
348
  parameter and false is returned. If there is no such character set,
 
349
  "default_cs" is assigned to the "cs" and true is returned.
 
350
 
 
351
  @param[in] cs_name    Character set name.
 
352
  @param[in] default_cs Default character set.
 
353
  @param[out] cs        Variable to store character set.
 
354
 
 
355
  @return false if character set was resolved successfully; true if there
 
356
  is no character set with given name.
 
357
*/
 
358
 
 
359
bool resolve_charset(const char *cs_name,
 
360
                     const CHARSET_INFO *default_cs,
 
361
                     const CHARSET_INFO **cs)
 
362
{
 
363
  *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
 
364
 
 
365
  if (*cs == NULL)
 
366
  {
 
367
    *cs= default_cs;
 
368
    return true;
 
369
  }
 
370
 
 
371
  return false;
 
372
}
 
373
 
 
374
 
 
375
/**
 
376
  Resolve collation by the collation name (utf8_general_ci, ...).
 
377
 
 
378
  The function tries to resolve collation by the specified name. If there
 
379
  is collation with the given name, it is assigned to the "cl" parameter
 
380
  and false is returned. If there is no such collation, "default_cl" is
 
381
  assigned to the "cl" and true is returned.
 
382
 
 
383
  @param[out] cl        Variable to store collation.
 
384
  @param[in] cl_name    Collation name.
 
385
  @param[in] default_cl Default collation.
 
386
 
 
387
  @return false if collation was resolved successfully; true if there is no
 
388
  collation with given name.
 
389
*/
 
390
 
 
391
bool resolve_collation(const char *cl_name,
 
392
                       const CHARSET_INFO *default_cl,
 
393
                       const CHARSET_INFO **cl)
 
394
{
 
395
  *cl= get_charset_by_name(cl_name, MYF(0));
 
396
 
 
397
  if (*cl == NULL)
 
398
  {
 
399
    *cl= default_cl;
 
400
    return true;
 
401
  }
 
402
 
 
403
  return false;
 
404
}
 
405
 
 
406
 
 
407
#ifdef BACKSLASH_MBTAIL
 
408
static CHARSET_INFO *fs_cset_cache= NULL;
 
409
 
 
410
CHARSET_INFO *fs_character_set()
 
411
{
 
412
  if (!fs_cset_cache)
 
413
  {
 
414
    char buf[10]= "cp";
 
415
    GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
 
416
                  buf+2, sizeof(buf)-3);
 
417
    /*
 
418
      We cannot call get_charset_by_name here
 
419
      because fs_character_set() is executed before
 
420
      LOCK_THD_charset mutex initialization, which
 
421
      is used inside get_charset_by_name.
 
422
      As we're now interested in cp932 only,
 
423
      let's just detect it using strcmp().
 
424
    */
 
425
    fs_cset_cache= !strcmp(buf, "cp932") ?
 
426
                   &my_charset_cp932_japanese_ci : &my_charset_bin;
 
427
  }
 
428
  return fs_cset_cache;
 
429
}
 
430
#endif
 
431
 
308
432
/*
309
433
  Escape apostrophes by doubling them up
310
434
 
337
461
  const char *to_start= to;
338
462
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
339
463
  bool overflow= false;
 
464
#ifdef USE_MB
340
465
  bool use_mb_flag= use_mb(charset_info);
 
466
#endif
341
467
  for (end= from + length; from < end; from++)
342
468
  {
 
469
#ifdef USE_MB
343
470
    int tmp_length;
344
471
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
345
472
    {
358
485
      turned into a multi-byte character by the addition of an escaping
359
486
      character, because we are only escaping the ' character with itself.
360
487
     */
 
488
#endif
361
489
    if (*from == '\'')
362
490
    {
363
491
      if (to + 2 > to_end)
381
509
  *to= 0;
382
510
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
383
511
}
384
 
 
385
 
} /* namespace drizzled */