1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 MySQL
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.
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.
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
21
#ifdef USE_PRAGMA_IMPLEMENTATION
22
#pragma implementation // gcc: Class implementation
25
#include <drizzled/field/fstring.h>
27
#define LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE 128
28
#define DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE 128
30
/****************************************************************************
32
** A string may be varchar or binary
33
****************************************************************************/
35
/* Copy a string and fill with space */
36
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
39
const char *well_formed_error_pos;
40
const char *cannot_convert_error_pos;
41
const char *from_end_pos;
43
/* See the comment for Field_long::store(long long) */
44
assert(table->in_use == current_thd);
46
copy_length= well_formed_copy_nchars(field_charset,
47
(char*) ptr, field_length,
49
field_length / field_charset->mbmaxlen,
50
&well_formed_error_pos,
51
&cannot_convert_error_pos,
54
/* Append spaces if the string was shorter than the field. */
55
if (copy_length < field_length)
56
field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
57
field_length-copy_length,
58
field_charset->pad_char);
60
if (check_string_copy_error(this, well_formed_error_pos,
61
cannot_convert_error_pos, from + length, cs))
64
return report_if_important_data(from_end_pos, from + length);
68
int Field_string::store(int64_t nr, bool unsigned_val)
72
CHARSET_INFO *cs=charset();
73
l= (cs->cset->int64_t10_to_str)(cs,buff,sizeof(buff),
74
unsigned_val ? 10 : -10, nr);
75
return Field_string::store(buff,(uint)l,cs);
79
double Field_string::val_real(void)
83
CHARSET_INFO *cs= charset();
86
result= my_strntod(cs,(char*) ptr,field_length,&end,&error);
87
if (!table->in_use->no_errors &&
88
(error || (field_length != (uint32_t)(end - (char*) ptr) &&
89
!check_if_only_end_space(cs, end,
90
(char*) ptr + field_length))))
92
char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
93
String tmp(buf, sizeof(buf), cs);
94
tmp.copy((char*) ptr, field_length, cs);
95
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
96
ER_TRUNCATED_WRONG_VALUE,
97
ER(ER_TRUNCATED_WRONG_VALUE),
98
"DOUBLE", tmp.c_ptr());
104
int64_t Field_string::val_int(void)
108
CHARSET_INFO *cs= charset();
111
result= my_strntoll(cs, (char*) ptr,field_length,10,&end,&error);
112
if (!table->in_use->no_errors &&
113
(error || (field_length != (uint32_t)(end - (char*) ptr) &&
114
!check_if_only_end_space(cs, end,
115
(char*) ptr + field_length))))
117
char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
118
String tmp(buf, sizeof(buf), cs);
119
tmp.copy((char*) ptr, field_length, cs);
120
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
121
ER_TRUNCATED_WRONG_VALUE,
122
ER(ER_TRUNCATED_WRONG_VALUE),
123
"INTEGER", tmp.c_ptr());
129
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
132
/* See the comment for Field_long::store(long long) */
133
assert(table->in_use == current_thd);
135
if (table->in_use->variables.sql_mode &
136
MODE_PAD_CHAR_TO_FULL_LENGTH)
137
length= my_charpos(field_charset, ptr, ptr + field_length, field_length);
139
length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
141
val_ptr->set((const char*) ptr, length, field_charset);
146
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
148
int err= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr, field_length,
149
charset(), decimal_value);
150
if (!table->in_use->no_errors && err)
152
char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
153
CHARSET_INFO *cs= charset();
154
String tmp(buf, sizeof(buf), cs);
155
tmp.copy((char*) ptr, field_length, cs);
156
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
157
ER_TRUNCATED_WRONG_VALUE,
158
ER(ER_TRUNCATED_WRONG_VALUE),
159
"DECIMAL", tmp.c_ptr());
162
return decimal_value;
166
int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
170
if (field_charset->mbmaxlen != 1)
172
uint char_len= field_length/field_charset->mbmaxlen;
173
a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
174
b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
177
a_len= b_len= field_length;
179
We have to remove end space to be able to compare multi-byte-characters
180
like in latin_de 'ae' and 0xe4
182
return field_charset->coll->strnncollsp(field_charset,
189
void Field_string::sort_string(uchar *to,uint length)
191
uint tmp= my_strnxfrm(field_charset,
194
assert(tmp == length);
198
void Field_string::sql_type(String &res) const
200
THD *thd= table->in_use;
201
CHARSET_INFO *cs=res.charset();
204
length= cs->cset->snprintf(cs,(char*) res.ptr(),
205
res.alloced_length(), "%s(%d)",
206
((type() == DRIZZLE_TYPE_VAR_STRING &&
207
!thd->variables.new_mode) ?
208
(has_charset() ? "varchar" : "varbinary") :
209
(has_charset() ? "char" : "binary")),
210
(int) field_length / charset()->mbmaxlen);
212
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
213
has_charset() && (charset()->state & MY_CS_BINSORT))
214
res.append(STRING_WITH_LEN(" binary"));
218
uchar *Field_string::pack(uchar *to, const uchar *from,
220
bool low_byte_first __attribute__((unused)))
222
uint length= min(field_length,max_length);
223
uint local_char_length= max_length/field_charset->mbmaxlen;
224
if (length > local_char_length)
225
local_char_length= my_charpos(field_charset, from, from+length,
227
set_if_smaller(length, local_char_length);
228
while (length && from[length-1] == field_charset->pad_char)
231
// Length always stored little-endian
232
*to++= (uchar) length;
233
if (field_length > 255)
234
*to++= (uchar) (length >> 8);
236
// Store the actual bytes of the string
237
memcpy(to, from, length);
243
Unpack a string field from row data.
245
This method is used to unpack a string field from a master whose size
246
of the field is less than that of the slave. Note that there can be a
247
variety of field types represented with this class. Certain types like
248
ENUM or SET are processed differently. Hence, the upper byte of the
249
@c param_data argument contains the result of field->real_type() from
252
@param to Destination of the data
253
@param from Source of the data
254
@param param_data Real type (upper) and length (lower) values
256
@return New pointer into memory based on from + length of the data
259
Field_string::unpack(uchar *to,
262
bool low_byte_first __attribute__((unused)))
265
param_data ? min(param_data & 0x00ff, field_length) : field_length;
268
if (from_length > 255)
270
length= uint2korr(from);
274
length= (uint) *from++;
276
memcpy(to, from, length);
277
// Pad the string with the pad character of the fields charset
278
memset(to + length, field_charset->pad_char, field_length - length);
284
Save the field metadata for string fields.
286
Saves the real type in the first byte and the field length in the
287
second byte of the field metadata array at index of *metadata_ptr and
290
@param metadata_ptr First byte of field metadata
292
@returns number of bytes written to metadata_ptr
294
int Field_string::do_save_field_metadata(uchar *metadata_ptr)
296
*metadata_ptr= real_type();
297
*(metadata_ptr + 1)= field_length;
303
Compare two packed keys
310
insert_or_update 1 if this is an insert or update
318
int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
319
my_bool insert_or_update)
321
uint a_length, b_length;
324
a_length= uint2korr(a);
325
b_length= uint2korr(b);
331
a_length= (uint) *a++;
332
b_length= (uint) *b++;
334
return field_charset->coll->strnncollsp(field_charset,
342
Compare a packed key against row.
344
@param key Original key
345
@param length Key length. (May be less than field length)
346
@param insert_or_update 1 if this is an insert or update
356
int Field_string::pack_cmp(const uchar *key, uint length,
357
my_bool insert_or_update)
359
uint row_length, local_key_length;
363
local_key_length= uint2korr(key);
367
local_key_length= (uint) *key++;
369
/* Only use 'length' of key, not field_length */
371
while (end > ptr && end[-1] == ' ')
373
row_length= (uint) (end - ptr);
375
return field_charset->coll->strnncollsp(field_charset,
377
key, local_key_length,
382
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
385
return uint2korr(data_ptr)+2;
386
return (uint) *data_ptr + 1;
390
uint Field_string::max_packed_col_length(uint max_length)
392
return (max_length > 255 ? 2 : 1)+max_length;
396
uint Field_string::get_key_image(uchar *buff,
398
imagetype type_arg __attribute__((unused)))
400
uint bytes = my_charpos(field_charset, (char*) ptr,
401
(char*) ptr + field_length,
402
length / field_charset->mbmaxlen);
403
memcpy(buff, ptr, bytes);
405
field_charset->cset->fill(field_charset, (char*) buff + bytes,
406
length - bytes, field_charset->pad_char);
411
Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
415
if (type() != DRIZZLE_TYPE_VAR_STRING || keep_type)
416
field= Field::new_field(root, new_table, keep_type);
417
else if ((field= new Field_varstring(field_length, maybe_null(), field_name,
418
new_table->s, charset())))
421
Old VARCHAR field which should be modified to a VARCHAR on copy
422
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
423
to now VARCHAR fields.
425
field->init(new_table);
427
Normally orig_table is different from table only if field was created
428
via ::new_field. Here we alter the type of field, so ::new_field is
429
not applicable. But we still need to preserve the original field
430
metadata for the client-server protocol.
432
field->orig_table= orig_table;