~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/strfunc.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/* Some useful string utility functions used by the MySQL server */
17
 
#include "config.h"
18
17
 
19
 
#include "drizzled/strfunc.h"
20
 
#include "drizzled/typelib.h"
21
 
#include "drizzled/charset_info.h"
22
 
#include "drizzled/global_charset_info.h"
 
18
#include "mysql_priv.h"
23
19
 
24
20
/*
25
21
  Return bitmap for strings used in a set
42
38
 
43
39
static const char field_separator=',';
44
40
 
45
 
uint64_t find_set(TYPELIB *lib, const char *str, uint32_t length,
46
 
                  const CHARSET_INFO * const cs,
47
 
                  char **err_pos, uint32_t *err_len, bool *set_warning)
 
41
ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
 
42
                   char **err_pos, uint *err_len, bool *set_warning)
48
43
{
49
 
  const CHARSET_INFO * const strip= cs ? cs : &my_charset_utf8_general_ci;
 
44
  CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
50
45
  const char *end= str + strip->cset->lengthsp(strip, str, length);
51
 
  uint64_t found= 0;
 
46
  ulonglong found= 0;
52
47
  *err_pos= 0;                  // No error yet
53
48
  if (str != end)
54
49
  {
55
 
    const char *start= str;
 
50
    const char *start= str;    
56
51
    for (;;)
57
52
    {
58
53
      const char *pos= start;
59
 
      uint32_t var_len;
 
54
      uint var_len;
60
55
      int mblen= 1;
61
56
 
62
 
      for (; pos != end && *pos != field_separator; pos++) 
63
 
      {}
64
 
      var_len= (uint32_t) (pos - start);
65
 
      uint32_t find= cs ? find_type2(lib, start, var_len, cs) :
 
57
      if (cs && cs->mbminlen > 1)
 
58
      {
 
59
        for ( ; pos < end; pos+= mblen)
 
60
        {
 
61
          my_wc_t wc;
 
62
          if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos, 
 
63
                                               (const uchar *) end)) < 1)
 
64
            mblen= 1; // Not to hang on a wrong multibyte sequence
 
65
          if (wc == (my_wc_t) field_separator)
 
66
            break;
 
67
        }
 
68
      }
 
69
      else
 
70
        for (; pos != end && *pos != field_separator; pos++) ;
 
71
      var_len= (uint) (pos - start);
 
72
      uint find= cs ? find_type2(lib, start, var_len, cs) :
66
73
                      find_type(lib, start, var_len, (bool) 0);
67
74
      if (!find)
68
75
      {
71
78
        *set_warning= 1;
72
79
      }
73
80
      else
74
 
        found|= ((int64_t) 1 << (find - 1));
 
81
        found|= ((longlong) 1 << (find - 1));
75
82
      if (pos >= end)
76
83
        break;
77
84
      start= pos + mblen;
97
104
  > 0 position in TYPELIB->type_names +1
98
105
*/
99
106
 
100
 
uint32_t find_type(const TYPELIB *lib, const char *find, uint32_t length,
 
107
uint find_type(const TYPELIB *lib, const char *find, uint length,
101
108
               bool part_match)
102
109
{
103
 
  uint32_t found_count=0, found_pos=0;
 
110
  uint found_count=0, found_pos=0;
104
111
  const char *end= find+length;
105
112
  const char *i;
106
113
  const char *j;
107
 
  for (uint32_t pos=0 ; (j=lib->type_names[pos++]) ; )
 
114
  for (uint pos=0 ; (j=lib->type_names[pos++]) ; )
108
115
  {
109
 
    for (i=find ; i != end &&
110
 
           my_toupper(system_charset_info,*i) ==
 
116
    for (i=find ; i != end && 
 
117
           my_toupper(system_charset_info,*i) == 
111
118
           my_toupper(system_charset_info,*j) ; i++, j++) ;
112
119
    if (i == end)
113
120
    {
138
145
    >0  Offset+1 in typelib for matched string
139
146
*/
140
147
 
141
 
uint32_t find_type2(const TYPELIB *typelib, const char *x, uint32_t length,
142
 
                const CHARSET_INFO * const cs)
 
148
uint find_type2(const TYPELIB *typelib, const char *x, uint length,
 
149
                CHARSET_INFO *cs)
143
150
{
144
151
  int pos;
145
152
  const char *j;
 
153
  DBUG_ENTER("find_type2");
 
154
  DBUG_PRINT("enter",("x: '%.*s'  lib: 0x%lx", length, x, (long) typelib));
146
155
 
147
156
  if (!typelib->count)
148
157
  {
149
 
    return(0);
 
158
    DBUG_PRINT("exit",("no count"));
 
159
    DBUG_RETURN(0);
150
160
  }
151
161
 
152
162
  for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
153
163
  {
154
 
    if (!my_strnncoll(cs, (const unsigned char*) x, length,
155
 
                          (const unsigned char*) j, typelib->type_lengths[pos]))
156
 
      return(pos+1);
 
164
    if (!my_strnncoll(cs, (const uchar*) x, length,
 
165
                          (const uchar*) j, typelib->type_lengths[pos]))
 
166
      DBUG_RETURN(pos+1);
157
167
  }
158
 
  return(0);
 
168
  DBUG_PRINT("exit",("Couldn't find type"));
 
169
  DBUG_RETURN(0);
159
170
} /* find_type */
160
171
 
 
172
 
 
173
/*
 
174
  Un-hex all elements in a typelib
 
175
 
 
176
  SYNOPSIS
 
177
   unhex_type2()
 
178
   interval       TYPELIB (struct of pointer to values + lengths + count)
 
179
 
 
180
  NOTES
 
181
 
 
182
  RETURN
 
183
    N/A
 
184
*/
 
185
 
 
186
void unhex_type2(TYPELIB *interval)
 
187
{
 
188
  for (uint pos= 0; pos < interval->count; pos++)
 
189
  {
 
190
    char *from, *to;
 
191
    for (from= to= (char*) interval->type_names[pos]; *from; )
 
192
    {
 
193
      /*
 
194
        Note, hexchar_to_int(*from++) doesn't work
 
195
        one some compilers, e.g. IRIX. Looks like a compiler
 
196
        bug in inline functions in combination with arguments
 
197
        that have a side effect. So, let's use from[0] and from[1]
 
198
        and increment 'from' by two later.
 
199
      */
 
200
 
 
201
      *to++= (char) (hexchar_to_int(from[0]) << 4) +
 
202
                     hexchar_to_int(from[1]);
 
203
      from+= 2;
 
204
    }
 
205
    interval->type_lengths[pos] /= 2;
 
206
  }
 
207
}
 
208
 
 
209
 
 
210
/*
 
211
  Check if the first word in a string is one of the ones in TYPELIB
 
212
 
 
213
  SYNOPSIS
 
214
    check_word()
 
215
    lib         TYPELIB
 
216
    val         String to check
 
217
    end         End of input
 
218
    end_of_word Store value of last used byte here if we found word
 
219
 
 
220
  RETURN
 
221
    0    No matching value
 
222
    > 1  lib->type_names[#-1] matched
 
223
         end_of_word will point to separator character/end in 'val'
 
224
*/
 
225
 
 
226
uint check_word(TYPELIB *lib, const char *val, const char *end,
 
227
                const char **end_of_word)
 
228
{
 
229
  int res;
 
230
  const char *ptr;
 
231
 
 
232
  /* Fiend end of word */
 
233
  for (ptr= val ; ptr < end && my_isalpha(&my_charset_latin1, *ptr) ; ptr++)
 
234
    ;
 
235
  if ((res=find_type(lib, val, (uint) (ptr - val), 1)) > 0)
 
236
    *end_of_word= ptr;
 
237
  return res;
 
238
}
 
239
 
 
240
 
 
241
/*
 
242
  Converts a string between character sets
 
243
 
 
244
  SYNOPSIS
 
245
    strconvert()
 
246
    from_cs       source character set
 
247
    from          source, a null terminated string
 
248
    to            destination buffer
 
249
    to_length     destination buffer length
 
250
 
 
251
  NOTES
 
252
    'to' is always terminated with a '\0' character.
 
253
    If there is no enough space to convert whole string,
 
254
    only prefix is converted, and terminated with '\0'.
 
255
 
 
256
  RETURN VALUES
 
257
    result string length
 
258
*/
 
259
 
 
260
 
 
261
uint strconvert(CHARSET_INFO *from_cs, const char *from,
 
262
                CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors)
 
263
{
 
264
  int cnvres;
 
265
  my_wc_t wc;
 
266
  char *to_start= to;
 
267
  uchar *to_end= (uchar*) to + to_length - 1;
 
268
  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
 
269
  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
 
270
  uint error_count= 0;
 
271
 
 
272
  while (1)
 
273
  {
 
274
    /*
 
275
      Using 'from + 10' is safe:
 
276
      - it is enough to scan a single character in any character set.
 
277
      - if remaining string is shorter than 10, then mb_wc will return
 
278
        with error because of unexpected '\0' character.
 
279
    */
 
280
    if ((cnvres= (*mb_wc)(from_cs, &wc,
 
281
                          (uchar*) from, (uchar*) from + 10)) > 0)
 
282
    {
 
283
      if (!wc)
 
284
        break;
 
285
      from+= cnvres;
 
286
    }
 
287
    else if (cnvres == MY_CS_ILSEQ)
 
288
    {
 
289
      error_count++;
 
290
      from++;
 
291
      wc= '?';
 
292
    }
 
293
    else
 
294
      break; // Impossible char.
 
295
 
 
296
outp:
 
297
 
 
298
    if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
 
299
      to+= cnvres;
 
300
    else if (cnvres == MY_CS_ILUNI && wc != '?')
 
301
    {
 
302
      error_count++;
 
303
      wc= '?';
 
304
      goto outp;
 
305
    }
 
306
    else
 
307
      break;
 
308
  }
 
309
  *to= '\0';
 
310
  *errors= error_count;
 
311
  return (uint32) (to - to_start);
 
312
 
 
313
}
 
314
 
 
315
 
 
316
/*
 
317
  Searches for a LEX_STRING in an LEX_STRING array.
 
318
 
 
319
  SYNOPSIS
 
320
    find_string_in_array()
 
321
      heap    The array
 
322
      needle  The string to search for
 
323
 
 
324
  NOTE
 
325
    The last LEX_STRING in the array should have str member set to NULL
 
326
 
 
327
  RETURN VALUES
 
328
    -1   Not found
 
329
    >=0  Ordinal position
 
330
*/
 
331
 
 
332
int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
 
333
                         CHARSET_INFO * const cs)
 
334
{
 
335
  const LEX_STRING *pos;
 
336
  for (pos= haystack; pos->str; pos++)
 
337
    if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length,
 
338
                               (uchar *) needle->str, needle->length, 0))
 
339
    {
 
340
      return (pos - haystack);
 
341
    }
 
342
  return -1;
 
343
}