~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/fstring.cc

  • Committer: Brian Aker
  • Date: 2010-12-08 22:35:56 UTC
  • mfrom: (1819.9.158 update-innobase)
  • Revision ID: brian@tangent.org-20101208223556-37mi4omqg7lkjzf3
Merge in Stewart's changes, 1.3 changes.

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
 
 
22
 
#include <drizzled/server_includes.h>
23
 
#include <drizzled/field/fstring.h>
24
 
#include <drizzled/error.h>
25
 
#include <drizzled/table.h>
26
 
#include <drizzled/session.h>
27
 
 
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,uint32_t length, const CHARSET_INFO * const cs)
39
 
{
40
 
  uint32_t 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(int64_t) */
46
 
  assert(table->in_use == current_session);
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_session, 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_session, 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(int64_t) */
135
 
  assert(table->in_use == current_session);
136
 
  uint32_t length;
137
 
 
138
 
  length= field_charset->cset->lengthsp(field_charset, (const char*) ptr, field_length);
139
 
  val_ptr->set((const char*) ptr, length, field_charset);
140
 
 
141
 
  return val_ptr;
142
 
}
143
 
 
144
 
 
145
 
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
146
 
{
147
 
  int err= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr, field_length,
148
 
                          charset(), decimal_value);
149
 
  if (!table->in_use->no_errors && err)
150
 
  {
151
 
    char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
152
 
    const CHARSET_INFO * const cs= charset();
153
 
    String tmp(buf, sizeof(buf), cs);
154
 
    tmp.copy((char*) ptr, field_length, cs);
155
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
156
 
                        ER_TRUNCATED_WRONG_VALUE, 
157
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
158
 
                        "DECIMAL", tmp.c_ptr());
159
 
  }
160
 
 
161
 
  return decimal_value;
162
 
}
163
 
 
164
 
 
165
 
int Field_string::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
166
 
{
167
 
  uint32_t a_len, b_len;
168
 
 
169
 
  if (field_charset->mbmaxlen != 1)
170
 
  {
171
 
    uint32_t char_len= field_length/field_charset->mbmaxlen;
172
 
    a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
173
 
    b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
174
 
  }
175
 
  else
176
 
    a_len= b_len= field_length;
177
 
  /*
178
 
    We have to remove end space to be able to compare multi-byte-characters
179
 
    like in latin_de 'ae' and 0xe4
180
 
  */
181
 
  return field_charset->coll->strnncollsp(field_charset,
182
 
                                          a_ptr, a_len,
183
 
                                          b_ptr, b_len,
184
 
                                          0);
185
 
}
186
 
 
187
 
 
188
 
void Field_string::sort_string(unsigned char *to,uint32_t length)
189
 
{
190
 
  uint32_t tmp= my_strnxfrm(field_charset,
191
 
                                 to, length,
192
 
                                 ptr, field_length);
193
 
  assert(tmp == length);
194
 
}
195
 
 
196
 
 
197
 
void Field_string::sql_type(String &res) const
198
 
{
199
 
  Session *session= table->in_use;
200
 
  const CHARSET_INFO * const cs= res.charset();
201
 
  uint32_t length;
202
 
 
203
 
  length= cs->cset->snprintf(cs,(char*) res.ptr(),
204
 
                             res.alloced_length(), "%s(%d)",
205
 
                             ((type() == DRIZZLE_TYPE_VARCHAR &&
206
 
                               !session->variables.new_mode) ?
207
 
                              (has_charset() ? "varchar" : "varbinary") :
208
 
                              (has_charset() ? "char" : "binary")),
209
 
                             (int) field_length / charset()->mbmaxlen);
210
 
  res.length(length);
211
 
}
212
 
 
213
 
 
214
 
unsigned char *Field_string::pack(unsigned char *to, const unsigned char *from,
215
 
                          uint32_t max_length,
216
 
                          bool low_byte_first __attribute__((unused)))
217
 
{
218
 
  uint32_t length=      cmin(field_length,max_length);
219
 
  uint32_t local_char_length= max_length/field_charset->mbmaxlen;
220
 
  if (length > local_char_length)
221
 
    local_char_length= my_charpos(field_charset, from, from+length,
222
 
                                  local_char_length);
223
 
  set_if_smaller(length, local_char_length);
224
 
  while (length && from[length-1] == field_charset->pad_char)
225
 
    length--;
226
 
 
227
 
  // Length always stored little-endian
228
 
  *to++= (unsigned char) length;
229
 
  if (field_length > 255)
230
 
    *to++= (unsigned char) (length >> 8);
231
 
 
232
 
  // Store the actual bytes of the string
233
 
  memcpy(to, from, length);
234
 
  return to+length;
235
 
}
236
 
 
237
 
 
238
 
/**
239
 
   Unpack a string field from row data.
240
 
 
241
 
   This method is used to unpack a string field from a master whose size 
242
 
   of the field is less than that of the slave. Note that there can be a
243
 
   variety of field types represented with this class. Certain types like
244
 
   ENUM or SET are processed differently. Hence, the upper byte of the 
245
 
   @c param_data argument contains the result of field->real_type() from
246
 
   the master.
247
 
 
248
 
   @param   to         Destination of the data
249
 
   @param   from       Source of the data
250
 
   @param   param_data Real type (upper) and length (lower) values
251
 
 
252
 
   @return  New pointer into memory based on from + length of the data
253
 
*/
254
 
const unsigned char *
255
 
Field_string::unpack(unsigned char *to,
256
 
                     const unsigned char *from,
257
 
                     uint32_t param_data,
258
 
                     bool low_byte_first __attribute__((unused)))
259
 
{
260
 
  uint32_t from_length=
261
 
    param_data ? cmin(param_data & 0x00ff, field_length) : field_length;
262
 
  uint32_t length;
263
 
 
264
 
  if (from_length > 255)
265
 
  {
266
 
    length= uint2korr(from);
267
 
    from+= 2;
268
 
  }
269
 
  else
270
 
    length= (uint) *from++;
271
 
 
272
 
  memcpy(to, from, length);
273
 
  // Pad the string with the pad character of the fields charset
274
 
  memset(to + length, field_charset->pad_char, field_length - length);
275
 
  return from+length;
276
 
}
277
 
 
278
 
 
279
 
/**
280
 
   Save the field metadata for string fields.
281
 
 
282
 
   Saves the real type in the first byte and the field length in the 
283
 
   second byte of the field metadata array at index of *metadata_ptr and
284
 
   *(metadata_ptr + 1).
285
 
 
286
 
   @param   metadata_ptr   First byte of field metadata
287
 
 
288
 
   @returns number of bytes written to metadata_ptr
289
 
*/
290
 
int Field_string::do_save_field_metadata(unsigned char *metadata_ptr)
291
 
{
292
 
  *metadata_ptr= real_type();
293
 
  *(metadata_ptr + 1)= field_length;
294
 
  return 2;
295
 
}
296
 
 
297
 
 
298
 
/*
299
 
  Compare two packed keys
300
 
 
301
 
  SYNOPSIS
302
 
    pack_cmp()
303
 
     a                  New key
304
 
     b                  Original key
305
 
     length             Key length
306
 
     insert_or_update   1 if this is an insert or update
307
 
 
308
 
  RETURN
309
 
    < 0   a < b
310
 
    0     a = b
311
 
    > 0   a > b
312
 
*/
313
 
 
314
 
int Field_string::pack_cmp(const unsigned char *a, const unsigned char *b, uint32_t length,
315
 
                           bool insert_or_update)
316
 
{
317
 
  uint32_t a_length, b_length;
318
 
  if (length > 255)
319
 
  {
320
 
    a_length= uint2korr(a);
321
 
    b_length= uint2korr(b);
322
 
    a+= 2;
323
 
    b+= 2;
324
 
  }
325
 
  else
326
 
  {
327
 
    a_length= (uint) *a++;
328
 
    b_length= (uint) *b++;
329
 
  }
330
 
  return field_charset->coll->strnncollsp(field_charset,
331
 
                                          a, a_length,
332
 
                                          b, b_length,
333
 
                                          insert_or_update);
334
 
}
335
 
 
336
 
 
337
 
/**
338
 
  Compare a packed key against row.
339
 
 
340
 
  @param key                    Original key
341
 
  @param length         Key length. (May be less than field length)
342
 
  @param insert_or_update       1 if this is an insert or update
343
 
 
344
 
  @return
345
 
    < 0   row < key
346
 
  @return
347
 
    0     row = key
348
 
  @return
349
 
    > 0   row > key
350
 
*/
351
 
 
352
 
int Field_string::pack_cmp(const unsigned char *key, uint32_t length,
353
 
                           bool insert_or_update)
354
 
{
355
 
  uint32_t row_length, local_key_length;
356
 
  unsigned char *end;
357
 
  if (length > 255)
358
 
  {
359
 
    local_key_length= uint2korr(key);
360
 
    key+= 2;
361
 
  }
362
 
  else
363
 
    local_key_length= (uint) *key++;
364
 
  
365
 
  /* Only use 'length' of key, not field_length */
366
 
  end= ptr + length;
367
 
  while (end > ptr && end[-1] == ' ')
368
 
    end--;
369
 
  row_length= (uint) (end - ptr);
370
 
 
371
 
  return field_charset->coll->strnncollsp(field_charset,
372
 
                                          ptr, row_length,
373
 
                                          key, local_key_length,
374
 
                                          insert_or_update);
375
 
}
376
 
 
377
 
 
378
 
uint32_t Field_string::packed_col_length(const unsigned char *data_ptr, uint32_t length)
379
 
{
380
 
  if (length > 255)
381
 
    return uint2korr(data_ptr)+2;
382
 
  return (uint) *data_ptr + 1;
383
 
}
384
 
 
385
 
 
386
 
uint32_t Field_string::max_packed_col_length(uint32_t max_length)
387
 
{
388
 
  return (max_length > 255 ? 2 : 1)+max_length;
389
 
}
390
 
 
391
 
 
392
 
uint32_t Field_string::get_key_image(unsigned char *buff,
393
 
                                 uint32_t length,
394
 
                                 imagetype type_arg __attribute__((unused)))
395
 
{
396
 
  uint32_t bytes = my_charpos(field_charset, (char*) ptr,
397
 
                          (char*) ptr + field_length,
398
 
                          length / field_charset->mbmaxlen);
399
 
  memcpy(buff, ptr, bytes);
400
 
  if (bytes < length)
401
 
    field_charset->cset->fill(field_charset, (char*) buff + bytes,
402
 
                              length - bytes, field_charset->pad_char);
403
 
  return bytes;
404
 
}
405
 
 
406
 
 
407
 
Field *Field_string::new_field(MEM_ROOT *root, Table *new_table, bool keep_type)
408
 
{
409
 
  Field *field;
410
 
  field= Field::new_field(root, new_table, keep_type);
411
 
  return field;
412
 
}
413
 
 
414