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/fdecimal.h>
27
/****************************************************************************
29
****************************************************************************/
31
Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
32
uint32_t len_arg, uchar *null_ptr_arg,
34
enum utype unireg_check_arg,
35
const char *field_name_arg,
36
uint8_t dec_arg,bool zero_arg,
38
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
39
unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
41
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
42
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
43
assert((precision <= DECIMAL_MAX_PRECISION) &&
44
(dec <= DECIMAL_MAX_SCALE));
45
bin_size= my_decimal_get_binary_size(precision, dec);
49
Field_new_decimal::Field_new_decimal(uint32_t len_arg,
54
:Field_num((uchar*) 0, len_arg,
55
maybe_null_arg ? (uchar*) "": 0, 0,
56
NONE, name, dec_arg, 0, unsigned_arg)
58
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
59
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
60
assert((precision <= DECIMAL_MAX_PRECISION) &&
61
(dec <= DECIMAL_MAX_SCALE));
62
bin_size= my_decimal_get_binary_size(precision, dec);
66
int Field_new_decimal::reset(void)
68
store_value(&decimal_zero);
74
Generate max/min decimal value in case of overflow.
76
@param decimal_value buffer for value
77
@param sign sign of value which caused overflow
80
void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
83
max_my_decimal(decimal_value, precision, decimals());
87
my_decimal_set_zero(decimal_value);
89
decimal_value->sign(true);
96
Store decimal value in the binary buffer.
98
Checks if decimal_value fits into field size.
99
If it does, stores the decimal in the buffer using binary format.
100
Otherwise sets maximal number that can be stored in the field.
102
@param decimal_value my_decimal
110
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
114
/* check that we do not try to write negative value in unsigned field */
115
if (unsigned_flag && decimal_value->sign())
117
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
119
decimal_value= &decimal_zero;
122
if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
123
decimal_value, ptr, precision, dec)))
126
set_value_on_overflow(&buff, decimal_value->sign());
127
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
134
int Field_new_decimal::store(const char *from, uint length,
135
CHARSET_INFO *charset_arg)
138
my_decimal decimal_value;
140
if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
141
~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
142
from, length, charset_arg,
144
table->in_use->abort_on_warning)
146
/* Because "from" is not NUL-terminated and we use %s in the ER() */
148
from_as_str.copy(from, length, &my_charset_bin);
150
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR,
151
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
152
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
153
"decimal", from_as_str.c_ptr(), field_name,
154
(ulong) table->in_use->row_count);
160
case E_DEC_TRUNCATED:
161
set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DATA_TRUNCATED, 1);
164
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
165
set_value_on_overflow(&decimal_value, decimal_value.sign());
169
/* Because "from" is not NUL-terminated and we use %s in the ER() */
171
from_as_str.copy(from, length, &my_charset_bin);
173
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
174
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
175
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
176
"decimal", from_as_str.c_ptr(), field_name,
177
(ulong) table->in_use->row_count);
178
my_decimal_set_zero(&decimal_value);
184
store_value(&decimal_value);
191
Fix following when double2my_decimal when double2decimal
192
will return E_DEC_TRUNCATED always correctly
195
int Field_new_decimal::store(double nr)
197
my_decimal decimal_value;
200
err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
204
if (check_overflow(err))
205
set_value_on_overflow(&decimal_value, decimal_value.sign());
206
/* Only issue a warning if store_value doesn't issue an warning */
207
table->in_use->got_warning= 0;
209
if (store_value(&decimal_value))
211
else if (err && !table->in_use->got_warning)
212
err= warn_if_overflow(err);
217
int Field_new_decimal::store(int64_t nr, bool unsigned_val)
219
my_decimal decimal_value;
222
if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
223
nr, unsigned_val, &decimal_value)))
225
if (check_overflow(err))
226
set_value_on_overflow(&decimal_value, decimal_value.sign());
227
/* Only issue a warning if store_value doesn't issue an warning */
228
table->in_use->got_warning= 0;
230
if (store_value(&decimal_value))
232
else if (err && !table->in_use->got_warning)
233
err= warn_if_overflow(err);
238
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
240
return store_value(decimal_value);
244
int Field_new_decimal::store_time(MYSQL_TIME *ltime,
245
timestamp_type t_type __attribute__((unused)))
247
my_decimal decimal_value;
248
return store_value(date2my_decimal(ltime, &decimal_value));
252
double Field_new_decimal::val_real(void)
255
my_decimal decimal_value;
256
my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
261
int64_t Field_new_decimal::val_int(void)
264
my_decimal decimal_value;
265
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
271
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
273
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
275
return(decimal_value);
279
String *Field_new_decimal::val_str(String *val_buffer,
280
String *val_ptr __attribute__((unused)))
282
my_decimal decimal_value;
283
uint fixed_precision= decimal_precision ? precision : 0;
284
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
285
fixed_precision, dec, '0', val_buffer);
290
int Field_new_decimal::cmp(const uchar *a,const uchar*b)
292
return memcmp(a, b, bin_size);
296
void Field_new_decimal::sort_string(uchar *buff,
297
uint length __attribute__((unused)))
299
memcpy(buff, ptr, bin_size);
303
void Field_new_decimal::sql_type(String &str) const
305
CHARSET_INFO *cs= str.charset();
306
str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
307
"decimal(%d,%d)", precision, (int)dec));
313
Save the field metadata for new decimal fields.
315
Saves the precision in the first byte and decimals() in the second
316
byte of the field metadata array at index of *metadata_ptr and
319
@param metadata_ptr First byte of field metadata
321
@returns number of bytes written to metadata_ptr
323
int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr)
325
*metadata_ptr= precision;
326
*(metadata_ptr + 1)= decimals();
332
Returns the number of bytes field uses in row-based replication
335
This method is used in row-based replication to determine the number
336
of bytes that the field consumes in the row record format. This is
337
used to skip fields in the master that do not exist on the slave.
339
@param field_metadata Encoded size in field metadata
341
@returns The size of the field based on the field metadata.
343
uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
345
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
346
uint const source_decimal= field_metadata & 0x00ff;
347
uint const source_size= my_decimal_get_binary_size(source_precision,
349
return (source_size);
354
Check to see if field size is compatible with destination.
356
This method is used in row-based replication to verify that the slave's
357
field size is less than or equal to the master's field size. The
358
encoded field metadata (from the master or source) is decoded and compared
359
to the size of this field (the slave or destination).
361
@param field_metadata Encoded size in field metadata
363
@retval 0 if this field's size is < the source field's size
364
@retval 1 if this field's size is >= the source field's size
366
int Field_new_decimal::compatible_field_size(uint field_metadata)
369
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
370
uint const source_decimal= field_metadata & 0x00ff;
371
uint const source_size= my_decimal_get_binary_size(source_precision,
373
uint const destination_size= row_pack_length();
374
compatible= (source_size <= destination_size);
376
compatible= (source_precision <= precision) &&
377
(source_decimal <= decimals());
382
uint Field_new_decimal::is_equal(Create_field *new_field)
384
return ((new_field->sql_type == real_type()) &&
385
((new_field->flags & UNSIGNED_FLAG) ==
386
(uint) (flags & UNSIGNED_FLAG)) &&
387
((new_field->flags & AUTO_INCREMENT_FLAG) ==
388
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
389
(new_field->length == max_display_length()) &&
390
(new_field->decimals == dec));
395
Unpack a decimal field from row data.
397
This method is used to unpack a decimal or numeric field from a master
398
whose size of the field is less than that of the slave.
400
@param to Destination of the data
401
@param from Source of the data
402
@param param_data Precision (upper) and decimal (lower) values
404
@return New pointer into memory based on from + length of the data
407
Field_new_decimal::unpack(uchar* to,
413
return Field::unpack(to, from, param_data, low_byte_first);
415
uint from_precision= (param_data & 0xff00) >> 8U;
416
uint from_decimal= param_data & 0x00ff;
417
uint length=pack_length();
418
uint from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
419
uint len= (param_data && (from_pack_len < length)) ?
420
from_pack_len : length;
421
if ((from_pack_len && (from_pack_len < length)) ||
422
(from_precision < precision) ||
423
(from_decimal < decimals()))
426
If the master's data is smaller than the slave, we need to convert
427
the binary to decimal then resize the decimal converting it back to
428
a decimal and write that to the raw data buffer.
430
decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
432
dec.len= from_precision;
435
Note: bin2decimal does not change the length of the field. So it is
436
just the first step the resizing operation. The second step does the
437
resizing using the precision and decimals from the slave.
439
bin2decimal((uchar *)from, &dec, from_precision, from_decimal);
440
decimal2bin(&dec, to, precision, decimals());
443
memcpy(to, from, len); // Sizes are the same, just copy the data.