~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/charset.cc

  • Committer: Jay Pipes
  • Date: 2009-01-30 04:38:21 UTC
  • mto: This revision was merged to the branch mainline in revision 830.
  • Revision ID: jpipes@serialcoder-20090130043821-4d7jg2ftabefamxb
Fixes for the QUARTER() function to use new Temporal system and throw
errors on bad datetime values.

Added test case for QUARTER() function and modified func_time.test existing
test to correctly throw errors and report NULL, not 0 on NULL input.

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"
 
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>
22
20
#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;
 
21
 
34
22
 
35
23
/*
36
24
  The code below implements this functionality:
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*) malloc(256)))
74
62
    return 1;
75
63
    
76
 
  if (!(cs->ident_map= (unsigned char*) cs_alloc(256)))
 
64
  if (!(cs->ident_map= (unsigned char*) malloc(256)))
77
65
    return 1;
78
66
 
79
67
  state_map= cs->state_map;
86
74
      state_map[i]=(unsigned char) MY_LEX_IDENT;
87
75
    else if (my_isdigit(cs,i))
88
76
      state_map[i]=(unsigned char) MY_LEX_NUMBER_IDENT;
 
77
#if defined(USE_MB) && defined(USE_MB_IDENT)
89
78
    else if (my_mbcharlen(cs, i)>1)
90
79
      state_map[i]=(unsigned char) MY_LEX_IDENT;
 
80
#endif
91
81
    else if (my_isspace(cs,i))
92
82
      state_map[i]=(unsigned char) MY_LEX_SKIP;
93
83
    else
126
116
}
127
117
 
128
118
 
129
 
static bool charset_initialized= false;
 
119
#define MY_CHARSET_INDEX "Index.xml"
 
120
 
 
121
const char *charsets_dir= NULL;
 
122
static int charset_initialized=0;
 
123
 
 
124
 
 
125
char *get_charsets_dir(char *buf)
 
126
{
 
127
  char *res;
 
128
 
 
129
  if (charsets_dir != NULL)
 
130
    strncpy(buf, charsets_dir, FN_REFLEN-1);
 
131
  else
 
132
  {
 
133
    if (test_if_hard_path(PKGDATADIR) ||
 
134
        is_prefix(PKGDATADIR, PREFIX))
 
135
      sprintf(buf,"%s/%s",PKGDATADIR,CHARSET_DIR);
 
136
    else
 
137
      sprintf(buf,"%s/%s/%s",PREFIX,PKGDATADIR,CHARSET_DIR);
 
138
  }
 
139
  res= convert_dirname(buf,buf,NULL);
 
140
  return(res);
 
141
}
130
142
 
131
143
CHARSET_INFO *all_charsets[256];
132
144
const CHARSET_INFO *default_charset_info = &my_charset_utf8_general_ci;
139
151
 
140
152
void *cs_alloc(size_t size)
141
153
{
142
 
  void *ptr= malloc(size);
143
 
 
144
 
  memory_vector.push_back(ptr);
145
 
 
146
 
  return ptr;
 
154
  return malloc(size);
147
155
}
148
156
 
149
157
 
150
 
 
151
158
static bool init_available_charsets(myf myflags)
152
159
{
153
 
  bool error= false;
 
160
  char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
161
  bool error=false;
154
162
  /*
155
163
    We have to use charset_initialized to not lock on THR_LOCK_charset
156
164
    inside get_internal_charset...
157
165
  */
158
 
  if (charset_initialized == false)
 
166
  if (!charset_initialized)
159
167
  {
160
168
    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++)
 
169
    /*
 
170
      To make things thread safe we are not allowing other threads to interfere
 
171
      while we may changing the cs_info_table
 
172
    */
 
173
    pthread_mutex_lock(&THR_LOCK_charset);
 
174
    if (!charset_initialized)
168
175
    {
169
 
      if (*cs)
 
176
      memset(&all_charsets, 0, sizeof(all_charsets));
 
177
      init_compiled_charsets(myflags);
 
178
 
 
179
      /* Copy compiled charsets */
 
180
      for (cs=all_charsets;
 
181
           cs < all_charsets+array_elements(all_charsets)-1 ;
 
182
           cs++)
170
183
      {
171
 
        if (cs[0]->ctype)
172
 
          if (init_state_maps(*cs))
173
 
            *cs= NULL;
 
184
        if (*cs)
 
185
        {
 
186
          if (cs[0]->ctype)
 
187
            if (init_state_maps(*cs))
 
188
              *cs= NULL;
 
189
        }
174
190
      }
 
191
 
 
192
      strcpy(get_charsets_dir(fname), MY_CHARSET_INDEX);
 
193
      charset_initialized=1;
175
194
    }
176
 
 
177
 
    charset_initialized= true;
 
195
    pthread_mutex_unlock(&THR_LOCK_charset);
178
196
  }
179
 
  assert(charset_initialized);
180
 
 
181
197
  return error;
182
198
}
183
199
 
184
200
 
185
201
void free_charsets(void)
186
202
{
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
 
 
 
203
  charset_initialized=0;
197
204
}
198
205
 
199
206
 
241
248
    To make things thread safe we are not allowing other threads to interfere
242
249
    while we may changing the cs_info_table
243
250
  */
 
251
  pthread_mutex_lock(&THR_LOCK_charset);
244
252
  if ((cs= all_charsets[cs_number]))
245
253
  {
246
254
    if (!(cs->state & MY_CS_COMPILED) && !(cs->state & MY_CS_LOADED))
257
265
    else
258
266
      cs->state|= MY_CS_READY;
259
267
  }
260
 
 
 
268
  pthread_mutex_unlock(&THR_LOCK_charset);
261
269
  return cs;
262
270
}
263
271
 
264
272
 
265
 
const CHARSET_INFO *get_charset(uint32_t cs_number)
 
273
const CHARSET_INFO *get_charset(uint32_t cs_number, myf flags)
266
274
{
267
275
  const CHARSET_INFO *cs;
268
276
  if (cs_number == default_charset_info->number)
275
283
 
276
284
  cs= get_internal_charset(cs_number);
277
285
 
 
286
  if (!cs && (flags & MY_WME))
 
287
  {
 
288
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
 
289
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
290
    cs_string[0]='#';
 
291
    int10_to_str(cs_number, cs_string+1, 10);
 
292
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
 
293
  }
278
294
  return cs;
279
295
}
280
296
 
281
 
const CHARSET_INFO *get_charset_by_name(const char *cs_name)
 
297
const CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
282
298
{
283
299
  uint32_t cs_number;
284
300
  const CHARSET_INFO *cs;
285
301
  (void) init_available_charsets(MYF(0));       /* If it isn't initialized */
286
302
 
287
 
  cs_number= get_collation_number(cs_name);
 
303
  cs_number=get_collation_number(cs_name);
288
304
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
289
305
 
 
306
  if (!cs && (flags & MY_WME))
 
307
  {
 
308
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
309
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
310
    my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
 
311
  }
 
312
 
290
313
  return cs;
291
314
}
292
315
 
293
316
 
294
 
const CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint32_t cs_flags)
 
317
const CHARSET_INFO *get_charset_by_csname(const char *cs_name,
 
318
                                    uint32_t cs_flags,
 
319
                                    myf flags)
295
320
{
296
321
  uint32_t cs_number;
297
322
  const CHARSET_INFO *cs;
301
326
  cs_number= get_charset_number(cs_name, cs_flags);
302
327
  cs= cs_number ? get_internal_charset(cs_number) : NULL;
303
328
 
 
329
  if (!cs && (flags & MY_WME))
 
330
  {
 
331
    char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
 
332
    strcpy(get_charsets_dir(index_file),MY_CHARSET_INDEX);
 
333
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
 
334
  }
 
335
 
304
336
  return(cs);
305
337
}
306
338
 
307
339
 
 
340
/**
 
341
  Resolve character set by the character set name (utf8, latin1, ...).
 
342
 
 
343
  The function tries to resolve character set by the specified name. If
 
344
  there is character set with the given name, it is assigned to the "cs"
 
345
  parameter and false is returned. If there is no such character set,
 
346
  "default_cs" is assigned to the "cs" and true is returned.
 
347
 
 
348
  @param[in] cs_name    Character set name.
 
349
  @param[in] default_cs Default character set.
 
350
  @param[out] cs        Variable to store character set.
 
351
 
 
352
  @return false if character set was resolved successfully; true if there
 
353
  is no character set with given name.
 
354
*/
 
355
 
 
356
bool resolve_charset(const char *cs_name,
 
357
                     const CHARSET_INFO *default_cs,
 
358
                     const CHARSET_INFO **cs)
 
359
{
 
360
  *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
 
361
 
 
362
  if (*cs == NULL)
 
363
  {
 
364
    *cs= default_cs;
 
365
    return true;
 
366
  }
 
367
 
 
368
  return false;
 
369
}
 
370
 
 
371
 
 
372
/**
 
373
  Resolve collation by the collation name (utf8_general_ci, ...).
 
374
 
 
375
  The function tries to resolve collation by the specified name. If there
 
376
  is collation with the given name, it is assigned to the "cl" parameter
 
377
  and false is returned. If there is no such collation, "default_cl" is
 
378
  assigned to the "cl" and true is returned.
 
379
 
 
380
  @param[out] cl        Variable to store collation.
 
381
  @param[in] cl_name    Collation name.
 
382
  @param[in] default_cl Default collation.
 
383
 
 
384
  @return false if collation was resolved successfully; true if there is no
 
385
  collation with given name.
 
386
*/
 
387
 
 
388
bool resolve_collation(const char *cl_name,
 
389
                       const CHARSET_INFO *default_cl,
 
390
                       const CHARSET_INFO **cl)
 
391
{
 
392
  *cl= get_charset_by_name(cl_name, MYF(0));
 
393
 
 
394
  if (*cl == NULL)
 
395
  {
 
396
    *cl= default_cl;
 
397
    return true;
 
398
  }
 
399
 
 
400
  return false;
 
401
}
 
402
 
 
403
 
 
404
#ifdef BACKSLASH_MBTAIL
 
405
static CHARSET_INFO *fs_cset_cache= NULL;
 
406
 
 
407
CHARSET_INFO *fs_character_set()
 
408
{
 
409
  if (!fs_cset_cache)
 
410
  {
 
411
    char buf[10]= "cp";
 
412
    GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
 
413
                  buf+2, sizeof(buf)-3);
 
414
    /*
 
415
      We cannot call get_charset_by_name here
 
416
      because fs_character_set() is executed before
 
417
      LOCK_THD_charset mutex initialization, which
 
418
      is used inside get_charset_by_name.
 
419
      As we're now interested in cp932 only,
 
420
      let's just detect it using strcmp().
 
421
    */
 
422
    fs_cset_cache= !strcmp(buf, "cp932") ?
 
423
                   &my_charset_cp932_japanese_ci : &my_charset_bin;
 
424
  }
 
425
  return fs_cset_cache;
 
426
}
 
427
#endif
 
428
 
308
429
/*
309
430
  Escape apostrophes by doubling them up
310
431
 
337
458
  const char *to_start= to;
338
459
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
339
460
  bool overflow= false;
 
461
#ifdef USE_MB
340
462
  bool use_mb_flag= use_mb(charset_info);
 
463
#endif
341
464
  for (end= from + length; from < end; from++)
342
465
  {
 
466
#ifdef USE_MB
343
467
    int tmp_length;
344
468
    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
345
469
    {
358
482
      turned into a multi-byte character by the addition of an escaping
359
483
      character, because we are only escaping the ' character with itself.
360
484
     */
 
485
#endif
361
486
    if (*from == '\'')
362
487
    {
363
488
      if (to + 2 > to_end)
381
506
  *to= 0;
382
507
  return overflow ? UINT32_MAX : (uint32_t) (to - to_start);
383
508
}
384
 
 
385
 
} /* namespace drizzled */