~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/fstring.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:
1
 
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 MySQL
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
#ifdef USE_PRAGMA_IMPLEMENTATION
22
 
#pragma implementation                          // gcc: Class implementation
23
 
#endif
24
 
 
25
 
#include <drizzled/server_includes.h>
26
 
#include <drizzled/field/fstring.h>
27
 
#include <drizzled/drizzled_error_messages.h>
28
 
 
29
 
#define LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE 128
30
 
#define DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE 128
31
 
 
32
 
/****************************************************************************
33
 
** string type
34
 
** A string may be varchar or binary
35
 
****************************************************************************/
36
 
 
37
 
/* Copy a string and fill with space */
38
 
int Field_string::store(const char *from,uint length, const CHARSET_INFO * const cs)
39
 
{
40
 
  uint copy_length;
41
 
  const char *well_formed_error_pos;
42
 
  const char *cannot_convert_error_pos;
43
 
  const char *from_end_pos;
44
 
 
45
 
  /* See the comment for Field_long::store(long long) */
46
 
  assert(table->in_use == current_thd);
47
 
 
48
 
  copy_length= well_formed_copy_nchars(field_charset,
49
 
                                       (char*) ptr, field_length,
50
 
                                       cs, from, length,
51
 
                                       field_length / field_charset->mbmaxlen,
52
 
                                       &well_formed_error_pos,
53
 
                                       &cannot_convert_error_pos,
54
 
                                       &from_end_pos);
55
 
 
56
 
  /* Append spaces if the string was shorter than the field. */
57
 
  if (copy_length < field_length)
58
 
    field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
59
 
                              field_length-copy_length,
60
 
                              field_charset->pad_char);
61
 
 
62
 
  if (check_string_copy_error(this, well_formed_error_pos,
63
 
                              cannot_convert_error_pos, from + length, cs))
64
 
    return 2;
65
 
 
66
 
  return report_if_important_data(from_end_pos, from + length);
67
 
}
68
 
 
69
 
 
70
 
int Field_string::store(int64_t nr, bool unsigned_val)
71
 
{
72
 
  char buff[64];
73
 
  int  l;
74
 
  const CHARSET_INFO * const cs= charset();
75
 
  l= (cs->cset->int64_t10_to_str)(cs,buff,sizeof(buff),
76
 
                                   unsigned_val ? 10 : -10, nr);
77
 
  return Field_string::store(buff,(uint)l,cs);
78
 
}
79
 
 
80
 
 
81
 
double Field_string::val_real(void)
82
 
{
83
 
  int error;
84
 
  char *end;
85
 
  const CHARSET_INFO * const cs= charset();
86
 
  double result;
87
 
  
88
 
  result=  my_strntod(cs,(char*) ptr,field_length,&end,&error);
89
 
  if (!table->in_use->no_errors &&
90
 
      (error || (field_length != (uint32_t)(end - (char*) ptr) && 
91
 
                 !check_if_only_end_space(cs, end,
92
 
                                          (char*) ptr + field_length))))
93
 
  {
94
 
    char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
95
 
    String tmp(buf, sizeof(buf), cs);
96
 
    tmp.copy((char*) ptr, field_length, cs);
97
 
    push_warning_printf(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
98
 
                        ER_TRUNCATED_WRONG_VALUE, 
99
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
100
 
                        "DOUBLE", tmp.c_ptr());
101
 
  }
102
 
  return result;
103
 
}
104
 
 
105
 
 
106
 
int64_t Field_string::val_int(void)
107
 
{
108
 
  int error;
109
 
  char *end;
110
 
  const CHARSET_INFO * const cs= charset();
111
 
  int64_t result;
112
 
 
113
 
  result= my_strntoll(cs, (char*) ptr,field_length,10,&end,&error);
114
 
  if (!table->in_use->no_errors &&
115
 
      (error || (field_length != (uint32_t)(end - (char*) ptr) && 
116
 
                 !check_if_only_end_space(cs, end,
117
 
                                          (char*) ptr + field_length))))
118
 
  {
119
 
    char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
120
 
    String tmp(buf, sizeof(buf), cs);
121
 
    tmp.copy((char*) ptr, field_length, cs);
122
 
    push_warning_printf(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
123
 
                        ER_TRUNCATED_WRONG_VALUE, 
124
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
125
 
                        "INTEGER", tmp.c_ptr());
126
 
  }
127
 
  return result;
128
 
}
129
 
 
130
 
 
131
 
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
132
 
                              String *val_ptr)
133
 
{
134
 
  /* See the comment for Field_long::store(long long) */
135
 
  assert(table->in_use == current_thd);
136
 
  uint length;
137
 
  if (table->in_use->variables.sql_mode &
138
 
      MODE_PAD_CHAR_TO_FULL_LENGTH)
139
 
    length= my_charpos(field_charset, ptr, ptr + field_length, field_length);
140
 
  else
141
 
    length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
142
 
                                          field_length);
143
 
  val_ptr->set((const char*) ptr, length, field_charset);
144
 
  return val_ptr;
145
 
}
146
 
 
147
 
 
148
 
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
149
 
{
150
 
  int err= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr, field_length,
151
 
                          charset(), decimal_value);
152
 
  if (!table->in_use->no_errors && err)
153
 
  {
154
 
    char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
155
 
    const CHARSET_INFO * const cs= charset();
156
 
    String tmp(buf, sizeof(buf), cs);
157
 
    tmp.copy((char*) ptr, field_length, cs);
158
 
    push_warning_printf(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
159
 
                        ER_TRUNCATED_WRONG_VALUE, 
160
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
161
 
                        "DECIMAL", tmp.c_ptr());
162
 
  }
163
 
 
164
 
  return decimal_value;
165
 
}
166
 
 
167
 
 
168
 
int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
169
 
{
170
 
  uint a_len, b_len;
171
 
 
172
 
  if (field_charset->mbmaxlen != 1)
173
 
  {
174
 
    uint char_len= field_length/field_charset->mbmaxlen;
175
 
    a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
176
 
    b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
177
 
  }
178
 
  else
179
 
    a_len= b_len= field_length;
180
 
  /*
181
 
    We have to remove end space to be able to compare multi-byte-characters
182
 
    like in latin_de 'ae' and 0xe4
183
 
  */
184
 
  return field_charset->coll->strnncollsp(field_charset,
185
 
                                          a_ptr, a_len,
186
 
                                          b_ptr, b_len,
187
 
                                          0);
188
 
}
189
 
 
190
 
 
191
 
void Field_string::sort_string(uchar *to,uint length)
192
 
{
193
 
  uint tmp= my_strnxfrm(field_charset,
194
 
                                 to, length,
195
 
                                 ptr, field_length);
196
 
  assert(tmp == length);
197
 
}
198
 
 
199
 
 
200
 
void Field_string::sql_type(String &res) const
201
 
{
202
 
  THD *thd= table->in_use;
203
 
  const CHARSET_INFO * const cs= res.charset();
204
 
  uint32_t length;
205
 
 
206
 
  length= cs->cset->snprintf(cs,(char*) res.ptr(),
207
 
                             res.alloced_length(), "%s(%d)",
208
 
                             ((type() == DRIZZLE_TYPE_VARCHAR &&
209
 
                               !thd->variables.new_mode) ?
210
 
                              (has_charset() ? "varchar" : "varbinary") :
211
 
                              (has_charset() ? "char" : "binary")),
212
 
                             (int) field_length / charset()->mbmaxlen);
213
 
  res.length(length);
214
 
}
215
 
 
216
 
 
217
 
uchar *Field_string::pack(uchar *to, const uchar *from,
218
 
                          uint max_length,
219
 
                          bool low_byte_first __attribute__((unused)))
220
 
{
221
 
  uint length=      min(field_length,max_length);
222
 
  uint local_char_length= max_length/field_charset->mbmaxlen;
223
 
  if (length > local_char_length)
224
 
    local_char_length= my_charpos(field_charset, from, from+length,
225
 
                                  local_char_length);
226
 
  set_if_smaller(length, local_char_length);
227
 
  while (length && from[length-1] == field_charset->pad_char)
228
 
    length--;
229
 
 
230
 
  // Length always stored little-endian
231
 
  *to++= (uchar) length;
232
 
  if (field_length > 255)
233
 
    *to++= (uchar) (length >> 8);
234
 
 
235
 
  // Store the actual bytes of the string
236
 
  memcpy(to, from, length);
237
 
  return to+length;
238
 
}
239
 
 
240
 
 
241
 
/**
242
 
   Unpack a string field from row data.
243
 
 
244
 
   This method is used to unpack a string field from a master whose size 
245
 
   of the field is less than that of the slave. Note that there can be a
246
 
   variety of field types represented with this class. Certain types like
247
 
   ENUM or SET are processed differently. Hence, the upper byte of the 
248
 
   @c param_data argument contains the result of field->real_type() from
249
 
   the master.
250
 
 
251
 
   @param   to         Destination of the data
252
 
   @param   from       Source of the data
253
 
   @param   param_data Real type (upper) and length (lower) values
254
 
 
255
 
   @return  New pointer into memory based on from + length of the data
256
 
*/
257
 
const uchar *
258
 
Field_string::unpack(uchar *to,
259
 
                     const uchar *from,
260
 
                     uint param_data,
261
 
                     bool low_byte_first __attribute__((unused)))
262
 
{
263
 
  uint from_length=
264
 
    param_data ? min(param_data & 0x00ff, field_length) : field_length;
265
 
  uint length;
266
 
 
267
 
  if (from_length > 255)
268
 
  {
269
 
    length= uint2korr(from);
270
 
    from+= 2;
271
 
  }
272
 
  else
273
 
    length= (uint) *from++;
274
 
 
275
 
  memcpy(to, from, length);
276
 
  // Pad the string with the pad character of the fields charset
277
 
  memset(to + length, field_charset->pad_char, field_length - length);
278
 
  return from+length;
279
 
}
280
 
 
281
 
 
282
 
/**
283
 
   Save the field metadata for string fields.
284
 
 
285
 
   Saves the real type in the first byte and the field length in the 
286
 
   second byte of the field metadata array at index of *metadata_ptr and
287
 
   *(metadata_ptr + 1).
288
 
 
289
 
   @param   metadata_ptr   First byte of field metadata
290
 
 
291
 
   @returns number of bytes written to metadata_ptr
292
 
*/
293
 
int Field_string::do_save_field_metadata(uchar *metadata_ptr)
294
 
{
295
 
  *metadata_ptr= real_type();
296
 
  *(metadata_ptr + 1)= field_length;
297
 
  return 2;
298
 
}
299
 
 
300
 
 
301
 
/*
302
 
  Compare two packed keys
303
 
 
304
 
  SYNOPSIS
305
 
    pack_cmp()
306
 
     a                  New key
307
 
     b                  Original key
308
 
     length             Key length
309
 
     insert_or_update   1 if this is an insert or update
310
 
 
311
 
  RETURN
312
 
    < 0   a < b
313
 
    0     a = b
314
 
    > 0   a > b
315
 
*/
316
 
 
317
 
int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
318
 
                           bool insert_or_update)
319
 
{
320
 
  uint a_length, b_length;
321
 
  if (length > 255)
322
 
  {
323
 
    a_length= uint2korr(a);
324
 
    b_length= uint2korr(b);
325
 
    a+= 2;
326
 
    b+= 2;
327
 
  }
328
 
  else
329
 
  {
330
 
    a_length= (uint) *a++;
331
 
    b_length= (uint) *b++;
332
 
  }
333
 
  return field_charset->coll->strnncollsp(field_charset,
334
 
                                          a, a_length,
335
 
                                          b, b_length,
336
 
                                          insert_or_update);
337
 
}
338
 
 
339
 
 
340
 
/**
341
 
  Compare a packed key against row.
342
 
 
343
 
  @param key                    Original key
344
 
  @param length         Key length. (May be less than field length)
345
 
  @param insert_or_update       1 if this is an insert or update
346
 
 
347
 
  @return
348
 
    < 0   row < key
349
 
  @return
350
 
    0     row = key
351
 
  @return
352
 
    > 0   row > key
353
 
*/
354
 
 
355
 
int Field_string::pack_cmp(const uchar *key, uint length,
356
 
                           bool insert_or_update)
357
 
{
358
 
  uint row_length, local_key_length;
359
 
  uchar *end;
360
 
  if (length > 255)
361
 
  {
362
 
    local_key_length= uint2korr(key);
363
 
    key+= 2;
364
 
  }
365
 
  else
366
 
    local_key_length= (uint) *key++;
367
 
  
368
 
  /* Only use 'length' of key, not field_length */
369
 
  end= ptr + length;
370
 
  while (end > ptr && end[-1] == ' ')
371
 
    end--;
372
 
  row_length= (uint) (end - ptr);
373
 
 
374
 
  return field_charset->coll->strnncollsp(field_charset,
375
 
                                          ptr, row_length,
376
 
                                          key, local_key_length,
377
 
                                          insert_or_update);
378
 
}
379
 
 
380
 
 
381
 
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
382
 
{
383
 
  if (length > 255)
384
 
    return uint2korr(data_ptr)+2;
385
 
  return (uint) *data_ptr + 1;
386
 
}
387
 
 
388
 
 
389
 
uint Field_string::max_packed_col_length(uint max_length)
390
 
{
391
 
  return (max_length > 255 ? 2 : 1)+max_length;
392
 
}
393
 
 
394
 
 
395
 
uint Field_string::get_key_image(uchar *buff,
396
 
                                 uint length,
397
 
                                 imagetype type_arg __attribute__((unused)))
398
 
{
399
 
  uint bytes = my_charpos(field_charset, (char*) ptr,
400
 
                          (char*) ptr + field_length,
401
 
                          length / field_charset->mbmaxlen);
402
 
  memcpy(buff, ptr, bytes);
403
 
  if (bytes < length)
404
 
    field_charset->cset->fill(field_charset, (char*) buff + bytes,
405
 
                              length - bytes, field_charset->pad_char);
406
 
  return bytes;
407
 
}
408
 
 
409
 
 
410
 
Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
411
 
                               bool keep_type)
412
 
{
413
 
  Field *field;
414
 
  field= Field::new_field(root, new_table, keep_type);
415
 
  return field;
416
 
}
417
 
 
418