~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/charset.cc

pandora-build v0.100 - Fixes several bugs found by cb1kenobi. Add several thoughts from folks at LCA.

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 "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
 
 
 
16
#include "config.h"
 
17
 
 
18
#include "drizzled/charset.h"
 
19
#include "drizzled/my_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
 
 
28
/*
 
29
  We collect memory in this vector that we free on delete.
 
30
*/
 
31
static vector<void *>memory_vector;
23
32
 
24
33
/*
25
34
  The code below implements this functionality:
26
 
  
 
35
 
27
36
    - Initializing charset related structures
28
37
    - Loading dynamic charsets
29
 
    - Searching for a proper CHARSET_INFO 
 
38
    - Searching for a proper CHARSET_INFO
30
39
      using charset name, collation name or collation ID
31
40
    - Setting server default character set
32
41
*/
45
54
       cs < all_charsets+array_elements(all_charsets)-1 ;
46
55
       cs++)
47
56
  {
48
 
    if ( cs[0] && cs[0]->name && 
49
 
         !my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
 
57
    if ( cs[0] && cs[0]->name &&
 
58
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
50
59
      return cs[0]->number;
51
 
  }  
 
60
  }
52
61
  return 0;
53
62
}
54
63
 
55
64
 
56
65
static bool init_state_maps(CHARSET_INFO *cs)
57
66
{
58
 
  uint i;
59
 
  uchar *state_map;
60
 
  uchar *ident_map;
 
67
  uint32_t i;
 
68
  unsigned char *state_map;
 
69
  unsigned char *ident_map;
61
70
 
62
 
  if (!(cs->state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
 
71
  if (!(cs->state_map= (unsigned char*) cs_alloc(256)))
63
72
    return 1;
64
73
    
65
 
  if (!(cs->ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
 
74
  if (!(cs->ident_map= (unsigned char*) cs_alloc(256)))
66
75
    return 1;
67
76
 
68
77
  state_map= cs->state_map;
69
78
  ident_map= cs->ident_map;
70
 
  
 
79
 
71
80
  /* Fill state_map with states to get a faster parser */
72
81
  for (i=0; i < 256 ; i++)
73
82
  {
74
83
    if (my_isalpha(cs,i))
75
 
      state_map[i]=(uchar) MY_LEX_IDENT;
 
84
      state_map[i]=(unsigned char) MY_LEX_IDENT;
76
85
    else if (my_isdigit(cs,i))
77
 
      state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
78
 
#if defined(USE_MB) && defined(USE_MB_IDENT)
 
86
      state_map[i]=(unsigned char) MY_LEX_NUMBER_IDENT;
79
87
    else if (my_mbcharlen(cs, i)>1)
80
 
      state_map[i]=(uchar) MY_LEX_IDENT;
81
 
#endif
 
88
      state_map[i]=(unsigned char) MY_LEX_IDENT;
82
89
    else if (my_isspace(cs,i))
83
 
      state_map[i]=(uchar) MY_LEX_SKIP;
 
90
      state_map[i]=(unsigned char) MY_LEX_SKIP;
84
91
    else
85
 
      state_map[i]=(uchar) MY_LEX_CHAR;
 
92
      state_map[i]=(unsigned char) MY_LEX_CHAR;
86
93
  }
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;
 
94
  state_map[(unsigned char)'_']=state_map[(unsigned char)'$']=(unsigned char) MY_LEX_IDENT;
 
95
  state_map[(unsigned char)'\'']=(unsigned char) MY_LEX_STRING;
 
96
  state_map[(unsigned char)'.']=(unsigned char) MY_LEX_REAL_OR_POINT;
 
97
  state_map[(unsigned char)'>']=state_map[(unsigned char)'=']=state_map[(unsigned char)'!']= (unsigned char) MY_LEX_CMP_OP;
 
98
  state_map[(unsigned char)'<']= (unsigned char) MY_LEX_LONG_CMP_OP;
 
99
  state_map[(unsigned char)'&']=state_map[(unsigned char)'|']=(unsigned char) MY_LEX_BOOL;
 
100
  state_map[(unsigned char)'#']=(unsigned char) MY_LEX_COMMENT;
 
101
  state_map[(unsigned char)';']=(unsigned char) MY_LEX_SEMICOLON;
 
102
  state_map[(unsigned char)':']=(unsigned char) MY_LEX_SET_VAR;
 
103
  state_map[0]=(unsigned char) MY_LEX_EOL;
 
104
  state_map[(unsigned char)'\\']= (unsigned char) MY_LEX_ESCAPE;
 
105
  state_map[(unsigned char)'/']= (unsigned char) MY_LEX_LONG_COMMENT;
 
106
  state_map[(unsigned char)'*']= (unsigned char) MY_LEX_END_LONG_COMMENT;
 
107
  state_map[(unsigned char)'@']= (unsigned char) MY_LEX_USER_END;
 
108
  state_map[(unsigned char) '`']= (unsigned char) MY_LEX_USER_VARIABLE_DELIMITER;
 
109
  state_map[(unsigned char)'"']= (unsigned char) MY_LEX_STRING_OR_DELIMITER;
103
110
 
104
111
  /*
105
112
    Create a second map to make it faster to find identifiers
106
113
  */
107
114
  for (i=0; i < 256 ; i++)
108
115
  {
109
 
    ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
 
116
    ident_map[i]= (unsigned char) (state_map[i] == MY_LEX_IDENT ||
110
117
                           state_map[i] == MY_LEX_NUMBER_IDENT);
111
118
  }
112
119
 
113
120
  /* Special handling of hex and binary strings */
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(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
 
}
 
121
  state_map[(unsigned char)'x']= state_map[(unsigned char)'X']= (unsigned char) MY_LEX_IDENT_OR_HEX;
 
122
  state_map[(unsigned char)'b']= state_map[(unsigned char)'B']= (unsigned char) MY_LEX_IDENT_OR_BIN;
 
123
  return 0;
 
124
}
 
125
 
 
126
 
 
127
static bool charset_initialized= false;
409
128
 
410
129
CHARSET_INFO *all_charsets[256];
411
 
const CHARSET_INFO *default_charset_info = &my_charset_latin1;
 
130
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
412
131
 
413
132
void add_compiled_collation(CHARSET_INFO * cs)
414
133
{
416
135
  cs->state|= MY_CS_AVAILABLE;
417
136
}
418
137
 
419
 
static void *cs_alloc(size_t size)
 
138
void *cs_alloc(size_t size)
420
139
{
421
 
  return my_once_alloc(size, MYF(MY_WME));
 
140
  void *ptr= malloc(size);
 
141
 
 
142
  memory_vector.push_back(ptr);
 
143
 
 
144
  return ptr;
422
145
}
423
146
 
424
147
 
 
148
 
425
149
static bool init_available_charsets(myf myflags)
426
150
{
427
 
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
428
 
  bool error=false;
 
151
  bool error= false;
429
152
  /*
430
153
    We have to use charset_initialized to not lock on THR_LOCK_charset
431
154
    inside get_internal_charset...
432
155
  */
433
 
  if (!charset_initialized)
 
156
  if (charset_initialized == false)
434
157
  {
435
158
    CHARSET_INFO **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)
 
159
    memset(&all_charsets, 0, sizeof(all_charsets));
 
160
    init_compiled_charsets(myflags);
 
161
 
 
162
    /* Copy compiled charsets */
 
163
    for (cs=all_charsets;
 
164
         cs < all_charsets+array_elements(all_charsets)-1 ;
 
165
         cs++)
442
166
    {
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++)
 
167
      if (*cs)
450
168
      {
451
 
        if (*cs)
452
 
        {
453
 
          if (cs[0]->ctype)
454
 
            if (init_state_maps(*cs))
455
 
              *cs= NULL;
456
 
        }
 
169
        if (cs[0]->ctype)
 
170
          if (init_state_maps(*cs))
 
171
            *cs= NULL;
457
172
      }
458
 
      
459
 
      stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
460
 
      error= my_read_charset_file(fname,myflags);
461
 
      charset_initialized=1;
462
173
    }
463
 
    pthread_mutex_unlock(&THR_LOCK_charset);
 
174
 
 
175
    charset_initialized= true;
464
176
  }
 
177
  assert(charset_initialized);
 
178
 
465
179
  return error;
466
180
}
467
181
 
468
182
 
469
183
void free_charsets(void)
470
184
{
471
 
  charset_initialized=0;
 
185
  charset_initialized= true;
 
186
 
 
187
  while (memory_vector.empty() == false)
 
188
  {
 
189
    void *ptr= memory_vector.back();
 
190
    memory_vector.pop_back();
 
191
    free(ptr);
 
192
  }
 
193
  memory_vector.clear();
 
194
 
472
195
}
473
196
 
474
197
 
475
 
uint get_collation_number(const char *name)
 
198
uint32_t get_collation_number(const char *name)
476
199
{
477
200
  init_available_charsets(MYF(0));
478
201
  return get_collation_number_internal(name);
479
202
}
480
203
 
481
204
 
482
 
uint get_charset_number(const char *charset_name, uint cs_flags)
 
205
uint32_t get_charset_number(const char *charset_name, uint32_t cs_flags)
483
206
{
484
207
  CHARSET_INFO **cs;
485
208
  init_available_charsets(MYF(0));
486
 
  
 
209
 
487
210
  for (cs= all_charsets;
488
211
       cs < all_charsets+array_elements(all_charsets)-1 ;
489
212
       cs++)
490
213
  {
491
214
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
492
 
         !my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
 
215
         !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
493
216
      return cs[0]->number;
494
 
  }  
 
217
  }
495
218
  return 0;
496
219
}
497
220
 
498
221
 
499
 
const char *get_charset_name(uint charset_number)
 
222
const char *get_charset_name(uint32_t charset_number)
500
223
{
501
224
  const CHARSET_INFO *cs;
502
225
  init_available_charsets(MYF(0));
504
227
  cs=all_charsets[charset_number];
505
228
  if (cs && (cs->number == charset_number) && cs->name )
506
229
    return (char*) cs->name;
507
 
  
 
230
 
508
231
  return (char*) "?";   /* this mimics find_type() */
509
232
}
510
233
 
511
234
 
512
 
static const CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
 
235
static const CHARSET_INFO *get_internal_charset(uint32_t cs_number)
513
236
{
514
 
  char  buf[FN_REFLEN];
515
237
  CHARSET_INFO *cs;
516
238
  /*
517
239
    To make things thread safe we are not allowing other threads to interfere
518
240
    while we may changing the cs_info_table
519
241
  */
520
 
  pthread_mutex_lock(&THR_LOCK_charset);
521
242
  if ((cs= all_charsets[cs_number]))
522
243
  {
523
244
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
524
245
    {
525
 
      strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
526
 
      my_read_charset_file(buf,flags);
 
246
      assert(0);
527
247
    }
528
248
    cs= (cs->state & MY_CS_AVAILABLE) ? cs : NULL;
529
249
  }
535
255
    else
536
256
      cs->state|= MY_CS_READY;
537
257
  }
538
 
  pthread_mutex_unlock(&THR_LOCK_charset);
 
258
 
539
259
  return cs;
540
260
}
541
261
 
542
262
 
543
 
const const CHARSET_INFO *get_charset(uint cs_number, myf flags)
 
263
const CHARSET_INFO *get_charset(uint32_t cs_number)
544
264
{
545
265
  const CHARSET_INFO *cs;
546
266
  if (cs_number == default_charset_info->number)
547
267
    return default_charset_info;
548
268
 
549
269
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
550
 
  
 
270
 
551
271
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
552
272
    return NULL;
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
 
    stpcpy(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
 
  }
 
273
 
 
274
  cs= get_internal_charset(cs_number);
 
275
 
564
276
  return cs;
565
277
}
566
278
 
567
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
 
279
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
568
280
{
569
 
  uint cs_number;
 
281
  uint32_t cs_number;
570
282
  const CHARSET_INFO *cs;
571
283
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
572
284
 
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
 
    stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
580
 
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
581
 
  }
 
285
  cs_number= get_collation_number(cs_name);
 
286
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
582
287
 
583
288
  return cs;
584
289
}
585
290
 
586
291
 
587
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
588
 
                                    uint cs_flags,
589
 
                                    myf flags)
 
292
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
590
293
{
591
 
  uint cs_number;
 
294
  uint32_t cs_number;
592
295
  const CHARSET_INFO *cs;
593
296
 
594
297
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
595
298
 
596
299
  cs_number= get_charset_number(cs_name, cs_flags);
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
 
    stpcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
603
 
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
604
 
  }
 
300
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
605
301
 
606
302
  return(cs);
607
303
}
608
304
 
609
305
 
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
 
                     const CHARSET_INFO *default_cs,
628
 
                     const 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
 
                       const CHARSET_INFO *default_cl,
660
 
                       const 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
 
 
814
306
/*
815
307
  Escape apostrophes by doubling them up
816
308
 
832
324
    mean "big enough"
833
325
 
834
326
  RETURN VALUES
835
 
    ~0          The escaped string did not fit in the to buffer
 
327
    UINT32_MAX  The escaped string did not fit in the to buffer
836
328
    >=0         The length of the escaped string
837
329
*/
838
330
 
843
335
  const char *to_start= to;
844
336
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
845
337
  bool overflow= false;
846
 
#ifdef USE_MB
847
338
  bool use_mb_flag= use_mb(charset_info);
848
 
#endif
849
339
  for (end= from + length; from < end; from++)
850
340
  {
851
 
#ifdef USE_MB
852
341
    int tmp_length;
853
342
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
854
343
    {
867
356
      turned into a multi-byte character by the addition of an escaping
868
357
      character, because we are only escaping the ' character with itself.
869
358
     */
870
 
#endif
871
359
    if (*from == '\'')
872
360
    {
873
361
      if (to + 2 > to_end)
889
377
    }
890
378
  }
891
379
  *to= 0;
892
 
  return overflow ? (uint32_t)~0 : (uint32_t) (to - to_start);
 
380
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
893
381
}