~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Monty
  • Date: 2008-10-02 05:41:33 UTC
  • mfrom: (398.1.10 codestyle)
  • Revision ID: mordred@scylla.inaugust.com-20081002054133-tyxv5bmqpazfaqqi
Merged up to 408 of stdint-includes-fix.

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
  uint i;
 
58
  uchar *state_map;
 
59
  uchar *ident_map;
 
60
 
 
61
  if (!(cs->state_map= (uchar*) 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= (uchar*) 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]=(uchar) MY_LEX_IDENT;
90
75
    else if (my_isdigit(cs,i))
91
 
      state_map[i]= MY_LEX_NUMBER_IDENT;
 
76
      state_map[i]=(uchar) 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]=(uchar) MY_LEX_IDENT;
 
80
#endif
94
81
    else if (my_isspace(cs,i))
95
 
      state_map[i]= MY_LEX_SKIP;
 
82
      state_map[i]=(uchar) MY_LEX_SKIP;
96
83
    else
97
 
      state_map[i]= MY_LEX_CHAR;
 
84
      state_map[i]=(uchar) 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[(uchar)'_']=state_map[(uchar)'$']=(uchar) MY_LEX_IDENT;
 
87
  state_map[(uchar)'\'']=(uchar) MY_LEX_STRING;
 
88
  state_map[(uchar)'.']=(uchar) MY_LEX_REAL_OR_POINT;
 
89
  state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) MY_LEX_CMP_OP;
 
90
  state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP;
 
91
  state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL;
 
92
  state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT;
 
93
  state_map[(uchar)';']=(uchar) MY_LEX_SEMICOLON;
 
94
  state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR;
 
95
  state_map[0]=(uchar) MY_LEX_EOL;
 
96
  state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE;
 
97
  state_map[(uchar)'/']= (uchar) MY_LEX_LONG_COMMENT;
 
98
  state_map[(uchar)'*']= (uchar) MY_LEX_END_LONG_COMMENT;
 
99
  state_map[(uchar)'@']= (uchar) MY_LEX_USER_END;
 
100
  state_map[(uchar) '`']= (uchar) MY_LEX_USER_VARIABLE_DELIMITER;
 
101
  state_map[(uchar)'"']= (uchar) 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]= (uchar) (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[(uchar)'x']= state_map[(uchar)'X']= (uchar) MY_LEX_IDENT_OR_HEX;
 
114
  state_map[(uchar)'b']= state_map[(uchar)'B']= (uchar) 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_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, NullS);
 
138
    else
 
139
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
 
140
              NullS);
 
141
  }
 
142
  res= convert_dirname(buf,buf,NullS);
 
143
  return(res);
 
144
}
 
145
 
 
146
CHARSET_INFO *all_charsets[256];
 
147
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
134
148
 
135
149
void add_compiled_collation(CHARSET_INFO * cs)
136
150
{
138
152
  cs->state|= MY_CS_AVAILABLE;
139
153
}
140
154
 
 
155
static void *cs_alloc(size_t size)
 
156
{
 
157
  return my_once_alloc(size, MYF(MY_WME));
 
158
}
 
159
 
 
160
 
141
161
static bool init_available_charsets(myf myflags)
142
162
{
143
 
  bool error= false;
 
163
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
164
  bool error=false;
144
165
  /*
145
166
    We have to use charset_initialized to not lock on THR_LOCK_charset
146
167
    inside get_internal_charset...
147
168
  */
148
 
  if (charset_initialized == false)
 
169
  if (!charset_initialized)
149
170
  {
150
171
    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++)
 
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)
158
178
    {
159
 
      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++)
160
186
      {
161
 
        if (cs[0]->ctype)
162
 
          if (init_state_maps(*cs))
163
 
            *cs= NULL;
 
187
        if (*cs)
 
188
        {
 
189
          if (cs[0]->ctype)
 
190
            if (init_state_maps(*cs))
 
191
              *cs= NULL;
 
192
        }
164
193
      }
 
194
      
 
195
      my_stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
196
      charset_initialized=1;
165
197
    }
166
 
 
167
 
    charset_initialized= true;
 
198
    pthread_mutex_unlock(&THR_LOCK_charset);
168
199
  }
169
 
  assert(charset_initialized);
170
 
 
171
200
  return error;
172
201
}
173
202
 
174
203
 
175
 
void free_charsets()
 
204
void free_charsets(void)
176
205
{
177
 
  charset_initialized= false;
178
 
 
179
 
  while (not memory_vector.empty())
180
 
  {
181
 
    delete[] memory_vector.back();
182
 
    memory_vector.pop_back();
183
 
  }
 
206
  charset_initialized=0;
184
207
}
185
208
 
186
209
 
187
 
uint32_t get_collation_number(const char *name)
 
210
uint get_collation_number(const char *name)
188
211
{
189
212
  init_available_charsets(MYF(0));
190
213
  return get_collation_number_internal(name);
191
214
}
192
215
 
193
216
 
194
 
uint32_t get_charset_number(const char *charset_name, uint32_t cs_flags)
 
217
uint get_charset_number(const char *charset_name, uint cs_flags)
195
218
{
196
219
  CHARSET_INFO **cs;
197
220
  init_available_charsets(MYF(0));
198
 
 
 
221
  
199
222
  for (cs= all_charsets;
200
223
       cs < all_charsets+array_elements(all_charsets)-1 ;
201
224
       cs++)
202
225
  {
203
 
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) && !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
 
226
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
 
227
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
204
228
      return cs[0]->number;
205
 
  }
 
229
  }  
206
230
  return 0;
207
231
}
208
232
 
209
233
 
210
 
const char *get_charset_name(uint32_t charset_number)
 
234
const char *get_charset_name(uint charset_number)
211
235
{
 
236
  const CHARSET_INFO *cs;
212
237
  init_available_charsets(MYF(0));
213
238
 
214
 
  const CHARSET_INFO *cs= all_charsets[charset_number];
 
239
  cs=all_charsets[charset_number];
215
240
  if (cs && (cs->number == charset_number) && cs->name )
216
 
    return cs->name;
217
 
 
218
 
  return "?";   /* this mimics find_type() */
 
241
    return (char*) cs->name;
 
242
  
 
243
  return (char*) "?";   /* this mimics find_type() */
219
244
}
220
245
 
221
246
 
222
 
static const CHARSET_INFO *get_internal_charset(uint32_t cs_number)
 
247
static const CHARSET_INFO *get_internal_charset(uint cs_number)
223
248
{
224
249
  CHARSET_INFO *cs;
225
250
  /*
226
251
    To make things thread safe we are not allowing other threads to interfere
227
252
    while we may changing the cs_info_table
228
253
  */
 
254
  pthread_mutex_lock(&THR_LOCK_charset);
229
255
  if ((cs= all_charsets[cs_number]))
230
256
  {
231
257
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
242
268
    else
243
269
      cs->state|= MY_CS_READY;
244
270
  }
245
 
 
 
271
  pthread_mutex_unlock(&THR_LOCK_charset);
246
272
  return cs;
247
273
}
248
274
 
249
275
 
250
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
276
const const CHARSET_INFO *get_charset(uint cs_number, myf flags)
251
277
{
252
278
  const CHARSET_INFO *cs;
253
279
  if (cs_number == default_charset_info->number)
254
280
    return default_charset_info;
255
281
 
256
282
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
257
 
 
 
283
  
258
284
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
259
285
    return NULL;
260
 
 
 
286
  
261
287
  cs= get_internal_charset(cs_number);
262
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
  }
263
297
  return cs;
264
298
}
265
299
 
266
 
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)
267
301
{
268
 
  uint32_t cs_number;
 
302
  uint cs_number;
269
303
  const CHARSET_INFO *cs;
270
304
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
271
305
 
272
 
  cs_number= get_collation_number(cs_name);
 
306
  cs_number=get_collation_number(cs_name);
273
307
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
274
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
 
275
316
  return cs;
276
317
}
277
318
 
278
319
 
279
 
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
                                    uint cs_flags,
 
322
                                    myf flags)
280
323
{
281
 
  uint32_t cs_number;
 
324
  uint cs_number;
282
325
  const CHARSET_INFO *cs;
283
326
 
284
327
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
286
329
  cs_number= get_charset_number(cs_name, cs_flags);
287
330
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
288
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
 
289
339
  return(cs);
290
340
}
291
341
 
292
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
 
293
432
/*
294
433
  Escape apostrophes by doubling them up
295
434
 
322
461
  const char *to_start= to;
323
462
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
324
463
  bool overflow= false;
 
464
#ifdef USE_MB
325
465
  bool use_mb_flag= use_mb(charset_info);
 
466
#endif
326
467
  for (end= from + length; from < end; from++)
327
468
  {
 
469
#ifdef USE_MB
328
470
    int tmp_length;
329
471
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
330
472
    {
343
485
      turned into a multi-byte character by the addition of an escaping
344
486
      character, because we are only escaping the ' character with itself.
345
487
     */
 
488
#endif
346
489
    if (*from == '\'')
347
490
    {
348
491
      if (to + 2 > to_end)
364
507
    }
365
508
  }
366
509
  *to= 0;
367
 
  return overflow ? UINT32_MAX : to - to_start;
 
510
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
368
511
}
369
 
 
370
 
} /* namespace drizzled */