Drizzled Public API Documentation

decimal.cc
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 <config.h>
23 #include <drizzled/field/decimal.h>
24 #include <drizzled/error.h>
25 #include <drizzled/table.h>
26 #include <drizzled/session.h>
27 #include <drizzled/create_field.h>
28 
29 namespace drizzled {
30 
31 /****************************************************************************
32  ** File_decimal
33  ****************************************************************************/
34 
35 Field_decimal::Field_decimal(unsigned char *ptr_arg,
36  uint32_t len_arg,
37  unsigned char *null_ptr_arg,
38  unsigned char null_bit_arg,
39  enum utype unireg_check_arg,
40  const char *field_name_arg,
41  uint8_t dec_arg) :
42  Field_num(ptr_arg,
43  len_arg,
44  null_ptr_arg,
45  null_bit_arg,
46  unireg_check_arg,
47  field_name_arg,
48  dec_arg, false,
49  false)
50  {
51  precision= class_decimal_length_to_precision(len_arg, dec_arg, false);
52  set_if_smaller(precision, (uint32_t)DECIMAL_MAX_PRECISION);
53  assert((precision <= DECIMAL_MAX_PRECISION) && (dec <= DECIMAL_MAX_SCALE));
54  bin_size= class_decimal_get_binary_size(precision, dec);
55  }
56 
57 Field_decimal::Field_decimal(uint32_t len_arg,
58  bool maybe_null_arg,
59  const char *name,
60  uint8_t dec_arg,
61  bool unsigned_arg) :
62  Field_num((unsigned char*) 0,
63  len_arg,
64  maybe_null_arg ? (unsigned char*) "": 0,
65  0,
66  NONE,
67  name,
68  dec_arg,
69  0,
70  unsigned_arg)
71 {
72  precision= class_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
73  set_if_smaller(precision, (uint32_t)DECIMAL_MAX_PRECISION);
74  assert((precision <= DECIMAL_MAX_PRECISION) &&
75  (dec <= DECIMAL_MAX_SCALE));
76  bin_size= class_decimal_get_binary_size(precision, dec);
77 }
78 
79 
80 int Field_decimal::reset(void)
81 {
82  store_value(&decimal_zero);
83  return 0;
84 }
85 
86 
95  bool sign)
96 {
97  max_Decimal(decimal_value, precision, decimals());
98  if (sign)
99  decimal_value->sign(true);
100 
101  return;
102 }
103 
104 
120 bool Field_decimal::store_value(const type::Decimal *decimal_value)
121 {
122  int error= decimal_value->val_binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, ptr, precision, dec);
123 
124  if (warn_if_overflow(error))
125  {
126  if (error != E_DEC_TRUNCATED)
127  {
128  type::Decimal buff;
129  set_value_on_overflow(&buff, decimal_value->sign());
130  buff.val_binary(E_DEC_FATAL_ERROR, ptr, precision, dec);
131  }
132  error= 1;
133  }
134 
135  return(error);
136 }
137 
138 
139 int Field_decimal::store(const char *from, uint32_t length,
140  const charset_info_st * const charset_arg)
141 {
142  int err;
143  type::Decimal decimal_value;
144 
145  ASSERT_COLUMN_MARKED_FOR_WRITE;
146 
147  if ((err= decimal_value.store(E_DEC_FATAL_ERROR &
148  ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
149  from, length, charset_arg)) &&
150  getTable()->in_use->abortOnWarning())
151  {
152  /* Because "from" is not NUL-terminated and we use %s in the ER() */
153  String from_as_str;
154  from_as_str.copy(from, length, &my_charset_bin);
155 
156  push_warning_printf(getTable()->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) getTable()->in_use->row_count);
161 
162  return(err);
163  }
164 
165  switch (err) {
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());
169  break;
170  case E_DEC_OVERFLOW:
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());
173  break;
174  case E_DEC_BAD_NUM:
175  {
176  /* Because "from" is not NUL-terminated and we use %s in the ER() */
177  String from_as_str;
178  from_as_str.copy(from, length, &my_charset_bin);
179 
180  push_warning_printf(getTable()->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) getTable()->in_use->row_count);
185  decimal_value.set_zero();
186 
187  break;
188  }
189  }
190 
191  store_value(&decimal_value);
192  return(err);
193 }
194 
195 
202 int Field_decimal::store(double nr)
203 {
204  type::Decimal decimal_value;
205  int err;
206 
207  ASSERT_COLUMN_MARKED_FOR_WRITE;
208 
209  err= double2_class_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
210  &decimal_value);
211  if (err)
212  {
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  getTable()->in_use->got_warning= 0;
217  }
218  if (store_value(&decimal_value))
219  err= 1;
220  else if (err && !getTable()->in_use->got_warning)
221  err= warn_if_overflow(err);
222  return(err);
223 }
224 
225 
226 int Field_decimal::store(int64_t nr, bool unsigned_val)
227 {
228  type::Decimal decimal_value;
229  int err;
230 
231  ASSERT_COLUMN_MARKED_FOR_WRITE;
232 
233  if ((err= int2_class_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
234  nr, unsigned_val, &decimal_value)))
235  {
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  getTable()->in_use->got_warning= 0;
240  }
241  if (store_value(&decimal_value))
242  err= 1;
243  else if (err && not getTable()->in_use->got_warning)
244  err= warn_if_overflow(err);
245  return err;
246 }
247 
248 
250 {
251  return store_value(decimal_value);
252 }
253 
254 
256  type::timestamp_t )
257 {
258  type::Decimal decimal_value;
259  return store_value(date2_class_decimal(&ltime, &decimal_value));
260 }
261 
262 
263 double Field_decimal::val_real(void) const
264 {
265  double dbl;
266  type::Decimal decimal_value;
267 
268  ASSERT_COLUMN_MARKED_FOR_READ;
269 
270  class_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
271 
272  return dbl;
273 }
274 
275 
276 int64_t Field_decimal::val_int(void) const
277 {
278  int64_t i;
279  type::Decimal decimal_value;
280 
281  ASSERT_COLUMN_MARKED_FOR_READ;
282 
283  val_decimal(&decimal_value)->val_int32(E_DEC_FATAL_ERROR, false, &i);
284 
285  return i;
286 }
287 
288 
290 {
291  ASSERT_COLUMN_MARKED_FOR_READ;
292 
293  binary2_class_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
294  precision, dec);
295  return(decimal_value);
296 }
297 
298 
299 String *Field_decimal::val_str(String *val_buffer, String *) const
300 {
301  type::Decimal decimal_value;
302 
303  ASSERT_COLUMN_MARKED_FOR_READ;
304 
305  class_decimal2string(val_decimal(&decimal_value),
306  dec, val_buffer);
307  return val_buffer;
308 }
309 
310 
311 int Field_decimal::cmp(const unsigned char *a,const unsigned char*b)
312 {
313  return memcmp(a, b, bin_size);
314 }
315 
316 
317 void Field_decimal::sort_string(unsigned char *buff, uint32_t)
318 {
319  memcpy(buff, ptr, bin_size);
320 }
321 
334 uint32_t Field_decimal::pack_length_from_metadata(uint32_t field_metadata)
335 {
336  uint32_t const source_precision= (field_metadata >> 8U) & 0x00ff;
337  uint32_t const source_decimal= field_metadata & 0x00ff;
338  uint32_t const source_size= class_decimal_get_binary_size(source_precision,
339  source_decimal);
340  return (source_size);
341 }
342 
343 
344 uint32_t Field_decimal::is_equal(CreateField *new_field_ptr)
345 {
346  return ((new_field_ptr->sql_type == real_type()) &&
347  ((new_field_ptr->flags & UNSIGNED_FLAG) ==
348  (uint32_t) (flags & UNSIGNED_FLAG)) &&
349  ((new_field_ptr->flags & AUTO_INCREMENT_FLAG) ==
350  (uint32_t) (flags & AUTO_INCREMENT_FLAG)) &&
351  (new_field_ptr->length == max_display_length()) &&
352  (new_field_ptr->decimals == dec));
353 }
354 
355 
368 const unsigned char *
369 Field_decimal::unpack(unsigned char* to,
370  const unsigned char *from,
371  uint32_t param_data,
372  bool low_byte_first)
373 {
374  if (param_data == 0)
375  return Field::unpack(to, from, param_data, low_byte_first);
376 
377  uint32_t from_precision= (param_data & 0xff00) >> 8U;
378  uint32_t from_decimal= param_data & 0x00ff;
379  uint32_t length=pack_length();
380  uint32_t from_pack_len= class_decimal_get_binary_size(from_precision, from_decimal);
381  uint32_t len= (param_data && (from_pack_len < length)) ?
382  from_pack_len : length;
383  if ((from_pack_len && (from_pack_len < length)) ||
384  (from_precision < precision) ||
385  (from_decimal < decimals()))
386  {
387  /*
388  If the master's data is smaller than the slave, we need to convert
389  the binary to decimal then resize the decimal converting it back to
390  a decimal and write that to the raw data buffer.
391  */
392  decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
393  decimal_t conv_dec;
394  conv_dec.len= from_precision;
395  conv_dec.buf= dec_buf;
396  /*
397 Note: bin2decimal does not change the length of the field. So it is
398 just the first step the resizing operation. The second step does the
399 resizing using the precision and decimals from the slave.
400  */
401  bin2decimal((unsigned char *)from, &conv_dec, from_precision, from_decimal);
402  decimal2bin(&conv_dec, to, precision, decimals());
403  }
404  else
405  memcpy(to, from, len); // Sizes are the same, just copy the data.
406  return from+len;
407 }
408 
409 } /* namespace drizzled */