~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.c

  • Committer: Mark Atwood
  • Date: 2008-10-03 01:39:40 UTC
  • mto: This revision was merged to the branch mainline in revision 437.
  • Revision ID: mark@fallenpegasus.com-20081003013940-mvefjo725dltz41h
rename logging_noop to logging_query

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
#include <mystrings/my_xml.h>
 
22
 
36
23
 
37
24
/*
38
25
  The code below implements this functionality:
39
 
 
 
26
  
40
27
    - Initializing charset related structures
41
28
    - Loading dynamic charsets
42
 
    - Searching for a proper CHARSET_INFO
 
29
    - Searching for a proper CHARSET_INFO 
43
30
      using charset name, collation name or collation ID
44
31
    - Setting server default character set
45
32
*/
53
40
static uint
54
41
get_collation_number_internal(const char *name)
55
42
{
56
 
  for (CHARSET_INFO **cs= all_charsets;
57
 
       cs < all_charsets+array_elements(all_charsets)-1;
 
43
  CHARSET_INFO **cs;
 
44
  for (cs= all_charsets;
 
45
       cs < all_charsets+array_elements(all_charsets)-1 ;
58
46
       cs++)
59
47
  {
60
 
    if ( cs[0] && cs[0]->name && !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->name, name))
61
 
    {
 
48
    if ( cs[0] && cs[0]->name && 
 
49
         !my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
62
50
      return cs[0]->number;
63
 
    }
64
 
  }
 
51
  }  
65
52
  return 0;
66
53
}
67
54
 
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
55
 
74
56
static bool init_state_maps(CHARSET_INFO *cs)
75
57
{
76
 
  if (!(cs->state_map= cs_alloc(256)))
 
58
  uint i;
 
59
  uchar *state_map;
 
60
  uchar *ident_map;
 
61
 
 
62
  if (!(cs->state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
77
63
    return 1;
78
64
    
79
 
  if (!(cs->ident_map= cs_alloc(256)))
 
65
  if (!(cs->ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
80
66
    return 1;
81
67
 
82
 
  unsigned char *state_map= cs->state_map;
83
 
  unsigned char *ident_map= cs->ident_map;
84
 
 
 
68
  state_map= cs->state_map;
 
69
  ident_map= cs->ident_map;
 
70
  
85
71
  /* Fill state_map with states to get a faster parser */
86
 
  for (int i= 0; i < 256; i++)
 
72
  for (i=0; i < 256 ; i++)
87
73
  {
88
74
    if (my_isalpha(cs,i))
89
 
      state_map[i]= MY_LEX_IDENT;
 
75
      state_map[i]=(uchar) MY_LEX_IDENT;
90
76
    else if (my_isdigit(cs,i))
91
 
      state_map[i]= MY_LEX_NUMBER_IDENT;
 
77
      state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
 
78
#if defined(USE_MB) && defined(USE_MB_IDENT)
92
79
    else if (my_mbcharlen(cs, i)>1)
93
 
      state_map[i]= MY_LEX_IDENT;
 
80
      state_map[i]=(uchar) MY_LEX_IDENT;
 
81
#endif
94
82
    else if (my_isspace(cs,i))
95
 
      state_map[i]= MY_LEX_SKIP;
 
83
      state_map[i]=(uchar) MY_LEX_SKIP;
96
84
    else
97
 
      state_map[i]= MY_LEX_CHAR;
 
85
      state_map[i]=(uchar) MY_LEX_CHAR;
98
86
  }
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;
 
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;
115
103
 
116
104
  /*
117
105
    Create a second map to make it faster to find identifiers
118
106
  */
119
 
  for (int i= 0; i < 256; i++)
 
107
  for (i=0; i < 256 ; i++)
120
108
  {
121
 
    ident_map[i]= state_map[i] == MY_LEX_IDENT || state_map[i] == MY_LEX_NUMBER_IDENT;
 
109
    ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
 
110
                           state_map[i] == MY_LEX_NUMBER_IDENT);
122
111
  }
123
112
 
124
113
  /* 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;
127
 
  return 0;
128
 
}
129
 
 
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;
 
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
}
 
409
 
 
410
CHARSET_INFO *all_charsets[256];
 
411
const CHARSET_INFO *default_charset_info = &my_charset_latin1;
134
412
 
135
413
void add_compiled_collation(CHARSET_INFO * cs)
136
414
{
138
416
  cs->state|= MY_CS_AVAILABLE;
139
417
}
140
418
 
 
419
static void *cs_alloc(size_t size)
 
420
{
 
421
  return my_once_alloc(size, MYF(MY_WME));
 
422
}
 
423
 
 
424
 
141
425
static bool init_available_charsets(myf myflags)
142
426
{
143
 
  bool error= false;
 
427
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
428
  bool error=false;
144
429
  /*
145
430
    We have to use charset_initialized to not lock on THR_LOCK_charset
146
431
    inside get_internal_charset...
147
432
  */
148
 
  if (charset_initialized == false)
 
433
  if (!charset_initialized)
149
434
  {
150
435
    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++)
 
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)
158
442
    {
159
 
      if (*cs)
 
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++)
160
450
      {
161
 
        if (cs[0]->ctype)
162
 
          if (init_state_maps(*cs))
163
 
            *cs= NULL;
 
451
        if (*cs)
 
452
        {
 
453
          if (cs[0]->ctype)
 
454
            if (init_state_maps(*cs))
 
455
              *cs= NULL;
 
456
        }
164
457
      }
 
458
      
 
459
      stpcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
460
      error= my_read_charset_file(fname,myflags);
 
461
      charset_initialized=1;
165
462
    }
166
 
 
167
 
    charset_initialized= true;
 
463
    pthread_mutex_unlock(&THR_LOCK_charset);
168
464
  }
169
 
  assert(charset_initialized);
170
 
 
171
465
  return error;
172
466
}
173
467
 
174
468
 
175
 
void free_charsets()
 
469
void free_charsets(void)
176
470
{
177
 
  charset_initialized= false;
178
 
 
179
 
  while (not memory_vector.empty())
180
 
  {
181
 
    delete[] memory_vector.back();
182
 
    memory_vector.pop_back();
183
 
  }
 
471
  charset_initialized=0;
184
472
}
185
473
 
186
474
 
187
 
uint32_t get_collation_number(const char *name)
 
475
uint get_collation_number(const char *name)
188
476
{
189
477
  init_available_charsets(MYF(0));
190
478
  return get_collation_number_internal(name);
191
479
}
192
480
 
193
481
 
194
 
uint32_t get_charset_number(const char *charset_name, uint32_t cs_flags)
 
482
uint get_charset_number(const char *charset_name, uint cs_flags)
195
483
{
196
484
  CHARSET_INFO **cs;
197
485
  init_available_charsets(MYF(0));
198
 
 
 
486
  
199
487
  for (cs= all_charsets;
200
488
       cs < all_charsets+array_elements(all_charsets)-1 ;
201
489
       cs++)
202
490
  {
203
 
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) && !my_strcasecmp(&my_charset_utf8_general_ci, cs[0]->csname, charset_name))
 
491
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
 
492
         !my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
204
493
      return cs[0]->number;
205
 
  }
 
494
  }  
206
495
  return 0;
207
496
}
208
497
 
209
498
 
210
 
const char *get_charset_name(uint32_t charset_number)
 
499
const char *get_charset_name(uint charset_number)
211
500
{
 
501
  const CHARSET_INFO *cs;
212
502
  init_available_charsets(MYF(0));
213
503
 
214
 
  const CHARSET_INFO *cs= all_charsets[charset_number];
 
504
  cs=all_charsets[charset_number];
215
505
  if (cs && (cs->number == charset_number) && cs->name )
216
 
    return cs->name;
217
 
 
218
 
  return "?";   /* this mimics find_type() */
 
506
    return (char*) cs->name;
 
507
  
 
508
  return (char*) "?";   /* this mimics find_type() */
219
509
}
220
510
 
221
511
 
222
 
static const CHARSET_INFO *get_internal_charset(uint32_t cs_number)
 
512
static const CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
223
513
{
 
514
  char  buf[FN_REFLEN];
224
515
  CHARSET_INFO *cs;
225
516
  /*
226
517
    To make things thread safe we are not allowing other threads to interfere
227
518
    while we may changing the cs_info_table
228
519
  */
 
520
  pthread_mutex_lock(&THR_LOCK_charset);
229
521
  if ((cs= all_charsets[cs_number]))
230
522
  {
231
523
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
232
524
    {
233
 
      assert(0);
 
525
      strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
 
526
      my_read_charset_file(buf,flags);
234
527
    }
235
528
    cs= (cs->state & MY_CS_AVAILABLE) ? cs : NULL;
236
529
  }
242
535
    else
243
536
      cs->state|= MY_CS_READY;
244
537
  }
245
 
 
 
538
  pthread_mutex_unlock(&THR_LOCK_charset);
246
539
  return cs;
247
540
}
248
541
 
249
542
 
250
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
543
const const CHARSET_INFO *get_charset(uint cs_number, myf flags)
251
544
{
252
545
  const CHARSET_INFO *cs;
253
546
  if (cs_number == default_charset_info->number)
254
547
    return default_charset_info;
255
548
 
256
549
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
257
 
 
 
550
  
258
551
  if (!cs_number || cs_number >= array_elements(all_charsets)-1)
259
552
    return NULL;
260
 
 
261
 
  cs= get_internal_charset(cs_number);
262
 
 
 
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
  }
263
564
  return cs;
264
565
}
265
566
 
266
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
 
567
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
267
568
{
268
 
  uint32_t cs_number;
 
569
  uint cs_number;
269
570
  const CHARSET_INFO *cs;
270
571
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
271
572
 
272
 
  cs_number= get_collation_number(cs_name);
273
 
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
 
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
  }
274
582
 
275
583
  return cs;
276
584
}
277
585
 
278
586
 
279
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
 
587
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
588
                                    uint cs_flags,
 
589
                                    myf flags)
280
590
{
281
 
  uint32_t cs_number;
 
591
  uint cs_number;
282
592
  const CHARSET_INFO *cs;
283
593
 
284
594
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
285
595
 
286
596
  cs_number= get_charset_number(cs_name, cs_flags);
287
 
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
 
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
  }
288
605
 
289
606
  return(cs);
290
607
}
291
608
 
292
609
 
 
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
 
293
814
/*
294
815
  Escape apostrophes by doubling them up
295
816
 
322
843
  const char *to_start= to;
323
844
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
324
845
  bool overflow= false;
 
846
#ifdef USE_MB
325
847
  bool use_mb_flag= use_mb(charset_info);
 
848
#endif
326
849
  for (end= from + length; from < end; from++)
327
850
  {
 
851
#ifdef USE_MB
328
852
    int tmp_length;
329
853
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
330
854
    {
343
867
      turned into a multi-byte character by the addition of an escaping
344
868
      character, because we are only escaping the ' character with itself.
345
869
     */
 
870
#endif
346
871
    if (*from == '\'')
347
872
    {
348
873
      if (to + 2 > to_end)
364
889
    }
365
890
  }
366
891
  *to= 0;
367
 
  return overflow ? UINT32_MAX : to - to_start;
 
892
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
368
893
}
369
 
 
370
 
} /* namespace drizzled */