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
23
#include <drizzled/field/decimal.h>
24
#include <drizzled/error.h>
25
#include <drizzled/table.h>
26
#include <drizzled/session.h>
28
extern my_decimal decimal_zero;
30
/****************************************************************************
32
****************************************************************************/
34
Field_decimal::Field_decimal(unsigned char *ptr_arg,
36
unsigned char *null_ptr_arg,
37
unsigned char null_bit_arg,
38
enum utype unireg_check_arg,
39
const char *field_name_arg,
52
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
53
set_if_smaller(precision, (uint32_t)DECIMAL_MAX_PRECISION);
54
assert((precision <= DECIMAL_MAX_PRECISION) &&
55
(dec <= DECIMAL_MAX_SCALE));
56
bin_size= my_decimal_get_binary_size(precision, dec);
59
Field_decimal::Field_decimal(uint32_t len_arg,
64
:Field_num((unsigned char*) 0,
66
maybe_null_arg ? (unsigned char*) "": 0,
74
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
75
set_if_smaller(precision, (uint32_t)DECIMAL_MAX_PRECISION);
76
assert((precision <= DECIMAL_MAX_PRECISION) &&
77
(dec <= DECIMAL_MAX_SCALE));
78
bin_size= my_decimal_get_binary_size(precision, dec);
82
int Field_decimal::reset(void)
84
store_value(&decimal_zero);
90
Generate max/min decimal value in case of overflow.
92
@param decimal_value buffer for value
93
@param sign sign of value which caused overflow
96
void Field_decimal::set_value_on_overflow(my_decimal *decimal_value,
99
max_my_decimal(decimal_value, precision, decimals());
101
decimal_value->sign(true);
108
Store decimal value in the binary buffer.
110
Checks if decimal_value fits into field size.
111
If it does, stores the decimal in the buffer using binary format.
112
Otherwise sets maximal number that can be stored in the field.
114
@param decimal_value my_decimal
122
bool Field_decimal::store_value(const my_decimal *decimal_value)
126
if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
127
decimal_value, ptr, precision, dec)))
130
set_value_on_overflow(&buff, decimal_value->sign());
131
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
138
int Field_decimal::store(const char *from, uint32_t length,
139
const CHARSET_INFO * const charset_arg)
142
my_decimal decimal_value;
144
ASSERT_COLUMN_MARKED_FOR_WRITE;
146
if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
147
~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
148
from, length, charset_arg,
150
table->in_use->abort_on_warning)
152
/* Because "from" is not NUL-terminated and we use %s in the ER() */
154
from_as_str.copy(from, length, &my_charset_bin);
156
push_warning_printf(table->in_use, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
157
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
158
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
159
"decimal", from_as_str.c_ptr(), field_name,
160
(uint32_t) table->in_use->row_count);
166
case E_DEC_TRUNCATED:
167
set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
168
set_value_on_overflow(&decimal_value, decimal_value.sign());
171
set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
172
set_value_on_overflow(&decimal_value, decimal_value.sign());
176
/* Because "from" is not NUL-terminated and we use %s in the ER() */
178
from_as_str.copy(from, length, &my_charset_bin);
180
push_warning_printf(table->in_use, DRIZZLE_ERROR::WARN_LEVEL_WARN,
181
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
182
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
183
"decimal", from_as_str.c_ptr(), field_name,
184
(uint32_t) table->in_use->row_count);
185
my_decimal_set_zero(&decimal_value);
191
store_value(&decimal_value);
198
Fix following when double2my_decimal when double2decimal
199
will return E_DEC_TRUNCATED always correctly
202
int Field_decimal::store(double nr)
204
my_decimal decimal_value;
207
ASSERT_COLUMN_MARKED_FOR_WRITE;
209
err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
213
if (check_overflow(err))
214
set_value_on_overflow(&decimal_value, decimal_value.sign());
215
/* Only issue a warning if store_value doesn't issue an warning */
216
table->in_use->got_warning= 0;
218
if (store_value(&decimal_value))
220
else if (err && !table->in_use->got_warning)
221
err= warn_if_overflow(err);
226
int Field_decimal::store(int64_t nr, bool unsigned_val)
228
my_decimal decimal_value;
231
ASSERT_COLUMN_MARKED_FOR_WRITE;
233
if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
234
nr, unsigned_val, &decimal_value)))
236
if (check_overflow(err))
237
set_value_on_overflow(&decimal_value, decimal_value.sign());
238
/* Only issue a warning if store_value doesn't issue an warning */
239
table->in_use->got_warning= 0;
241
if (store_value(&decimal_value))
243
else if (err && !table->in_use->got_warning)
244
err= warn_if_overflow(err);
249
int Field_decimal::store_decimal(const my_decimal *decimal_value)
251
return store_value(decimal_value);
255
int Field_decimal::store_time(DRIZZLE_TIME *ltime,
256
enum enum_drizzle_timestamp_type )
258
my_decimal decimal_value;
259
return store_value(date2my_decimal(ltime, &decimal_value));
263
double Field_decimal::val_real(void)
266
my_decimal decimal_value;
268
ASSERT_COLUMN_MARKED_FOR_READ;
270
my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
276
int64_t Field_decimal::val_int(void)
279
my_decimal decimal_value;
281
ASSERT_COLUMN_MARKED_FOR_READ;
283
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), false, &i);
289
my_decimal* Field_decimal::val_decimal(my_decimal *decimal_value)
291
ASSERT_COLUMN_MARKED_FOR_READ;
293
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
295
return(decimal_value);
299
String *Field_decimal::val_str(String *val_buffer,
302
my_decimal decimal_value;
304
ASSERT_COLUMN_MARKED_FOR_READ;
306
uint32_t fixed_precision= decimal_precision ? precision : 0;
307
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
308
fixed_precision, dec, '0', val_buffer);
313
int Field_decimal::cmp(const unsigned char *a,const unsigned char*b)
315
return memcmp(a, b, bin_size);
319
void Field_decimal::sort_string(unsigned char *buff,
322
memcpy(buff, ptr, bin_size);
326
void Field_decimal::sql_type(String &str) const
328
const CHARSET_INFO * const cs= str.charset();
329
str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
330
"decimal(%d,%d)", precision, (int)dec));
335
Returns the number of bytes field uses in row-based replication
338
This method is used in row-based replication to determine the number
339
of bytes that the field consumes in the row record format. This is
340
used to skip fields in the master that do not exist on the slave.
342
@param field_metadata Encoded size in field metadata
344
@returns The size of the field based on the field metadata.
346
uint32_t Field_decimal::pack_length_from_metadata(uint32_t field_metadata)
348
uint32_t const source_precision= (field_metadata >> 8U) & 0x00ff;
349
uint32_t const source_decimal= field_metadata & 0x00ff;
350
uint32_t const source_size= my_decimal_get_binary_size(source_precision,
352
return (source_size);
357
Check to see if field size is compatible with destination.
359
This method is used in row-based replication to verify that the slave's
360
field size is less than or equal to the master's field size. The
361
encoded field metadata (from the master or source) is decoded and compared
362
to the size of this field (the slave or destination).
364
@param field_metadata Encoded size in field metadata
366
@retval 0 if this field's size is < the source field's size
367
@retval 1 if this field's size is >= the source field's size
369
int Field_decimal::compatible_field_size(uint32_t field_metadata)
372
uint32_t const source_precision= (field_metadata >> 8U) & 0x00ff;
373
uint32_t const source_decimal= field_metadata & 0x00ff;
374
uint32_t const source_size= my_decimal_get_binary_size(source_precision,
376
uint32_t const destination_size= row_pack_length();
377
compatible= (source_size <= destination_size);
379
compatible= (source_precision <= precision) &&
380
(source_decimal <= decimals());
385
uint32_t Field_decimal::is_equal(CreateField *new_field_ptr)
387
return ((new_field_ptr->sql_type == real_type()) &&
388
((new_field_ptr->flags & UNSIGNED_FLAG) ==
389
(uint32_t) (flags & UNSIGNED_FLAG)) &&
390
((new_field_ptr->flags & AUTO_INCREMENT_FLAG) ==
391
(uint32_t) (flags & AUTO_INCREMENT_FLAG)) &&
392
(new_field_ptr->length == max_display_length()) &&
393
(new_field_ptr->decimals == dec));
398
Unpack a decimal field from row data.
400
This method is used to unpack a decimal or numeric field from a master
401
whose size of the field is less than that of the slave.
403
@param to Destination of the data
404
@param from Source of the data
405
@param param_data Precision (upper) and decimal (lower) values
407
@return New pointer into memory based on from + length of the data
409
const unsigned char *
410
Field_decimal::unpack(unsigned char* to,
411
const unsigned char *from,
416
return Field::unpack(to, from, param_data, low_byte_first);
418
uint32_t from_precision= (param_data & 0xff00) >> 8U;
419
uint32_t from_decimal= param_data & 0x00ff;
420
uint32_t length=pack_length();
421
uint32_t from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
422
uint32_t len= (param_data && (from_pack_len < length)) ?
423
from_pack_len : length;
424
if ((from_pack_len && (from_pack_len < length)) ||
425
(from_precision < precision) ||
426
(from_decimal < decimals()))
429
If the master's data is smaller than the slave, we need to convert
430
the binary to decimal then resize the decimal converting it back to
431
a decimal and write that to the raw data buffer.
433
decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
435
conv_dec.len= from_precision;
436
conv_dec.buf= dec_buf;
438
Note: bin2decimal does not change the length of the field. So it is
439
just the first step the resizing operation. The second step does the
440
resizing using the precision and decimals from the slave.
442
bin2decimal((unsigned char *)from, &conv_dec, from_precision, from_decimal);
443
decimal2bin(&conv_dec, to, precision, decimals());
446
memcpy(to, from, len); // Sizes are the same, just copy the data.