~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/fdecimal.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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
#ifdef USE_PRAGMA_IMPLEMENTATION
 
22
#pragma implementation                          // gcc: Class implementation
 
23
#endif
 
24
 
 
25
#include <drizzled/server_includes.h>
 
26
#include <drizzled/field/fdecimal.h>
 
27
#include <drizzled/drizzled_error_messages.h>
 
28
 
 
29
 
 
30
/****************************************************************************
 
31
** Field_new_decimal
 
32
****************************************************************************/
 
33
 
 
34
Field_new_decimal::Field_new_decimal(unsigned char *ptr_arg,
 
35
                                     uint32_t len_arg, unsigned char *null_ptr_arg,
 
36
                                     unsigned char null_bit_arg,
 
37
                                     enum utype unireg_check_arg,
 
38
                                     const char *field_name_arg,
 
39
                                     uint8_t dec_arg,bool zero_arg,
 
40
                                     bool unsigned_arg)
 
41
  :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
 
42
             unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
 
43
{
 
44
  precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
 
45
  set_if_smaller(precision, DECIMAL_MAX_PRECISION);
 
46
  assert((precision <= DECIMAL_MAX_PRECISION) &&
 
47
              (dec <= DECIMAL_MAX_SCALE));
 
48
  bin_size= my_decimal_get_binary_size(precision, dec);
 
49
}
 
50
 
 
51
 
 
52
Field_new_decimal::Field_new_decimal(uint32_t len_arg,
 
53
                                     bool maybe_null_arg,
 
54
                                     const char *name,
 
55
                                     uint8_t dec_arg,
 
56
                                     bool unsigned_arg)
 
57
  :Field_num((unsigned char*) 0, len_arg,
 
58
             maybe_null_arg ? (unsigned char*) "": 0, 0,
 
59
             NONE, name, dec_arg, 0, unsigned_arg)
 
60
{
 
61
  precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
 
62
  set_if_smaller(precision, DECIMAL_MAX_PRECISION);
 
63
  assert((precision <= DECIMAL_MAX_PRECISION) &&
 
64
              (dec <= DECIMAL_MAX_SCALE));
 
65
  bin_size= my_decimal_get_binary_size(precision, dec);
 
66
}
 
67
 
 
68
 
 
69
int Field_new_decimal::reset(void)
 
70
{
 
71
  store_value(&decimal_zero);
 
72
  return 0;
 
73
}
 
74
 
 
75
 
 
76
/**
 
77
  Generate max/min decimal value in case of overflow.
 
78
 
 
79
  @param decimal_value     buffer for value
 
80
  @param sign              sign of value which caused overflow
 
81
*/
 
82
 
 
83
void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
 
84
                                              bool sign)
 
85
{
 
86
  max_my_decimal(decimal_value, precision, decimals());
 
87
  if (sign)
 
88
  {
 
89
    if (unsigned_flag)
 
90
      my_decimal_set_zero(decimal_value);
 
91
    else
 
92
      decimal_value->sign(true);
 
93
  }
 
94
  return;
 
95
}
 
96
 
 
97
 
 
98
/**
 
99
  Store decimal value in the binary buffer.
 
100
 
 
101
  Checks if decimal_value fits into field size.
 
102
  If it does, stores the decimal in the buffer using binary format.
 
103
  Otherwise sets maximal number that can be stored in the field.
 
104
 
 
105
  @param decimal_value   my_decimal
 
106
 
 
107
  @retval
 
108
    0 ok
 
109
  @retval
 
110
    1 error
 
111
*/
 
112
 
 
113
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
 
114
{
 
115
  int error= 0;
 
116
 
 
117
  /* check that we do not try to write negative value in unsigned field */
 
118
  if (unsigned_flag && decimal_value->sign())
 
119
  {
 
120
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
 
121
    error= 1;
 
122
    decimal_value= &decimal_zero;
 
123
  }
 
124
 
 
125
  if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
 
126
                                         decimal_value, ptr, precision, dec)))
 
127
  {
 
128
    my_decimal buff;
 
129
    set_value_on_overflow(&buff, decimal_value->sign());
 
130
    my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
 
131
    error= 1;
 
132
  }
 
133
  return(error);
 
134
}
 
135
 
 
136
 
 
137
int Field_new_decimal::store(const char *from, uint32_t length,
 
138
                             const CHARSET_INFO * const charset_arg)
 
139
{
 
140
  int err;
 
141
  my_decimal decimal_value;
 
142
 
 
143
  if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
 
144
                           ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
 
145
                           from, length, charset_arg,
 
146
                           &decimal_value)) &&
 
147
      table->in_use->abort_on_warning)
 
148
  {
 
149
    /* Because "from" is not NUL-terminated and we use %s in the ER() */
 
150
    String from_as_str;
 
151
    from_as_str.copy(from, length, &my_charset_bin);
 
152
 
 
153
    push_warning_printf(table->in_use, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
154
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
 
155
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
 
156
                        "decimal", from_as_str.c_ptr(), field_name,
 
157
                        (uint32_t) table->in_use->row_count);
 
158
 
 
159
    return(err);
 
160
  }
 
161
 
 
162
  switch (err) {
 
163
  case E_DEC_TRUNCATED:
 
164
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_WARN_DATA_TRUNCATED, 1);
 
165
    break;
 
166
  case E_DEC_OVERFLOW:
 
167
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
 
168
    set_value_on_overflow(&decimal_value, decimal_value.sign());
 
169
    break;
 
170
  case E_DEC_BAD_NUM:
 
171
    {
 
172
      /* Because "from" is not NUL-terminated and we use %s in the ER() */
 
173
      String from_as_str;
 
174
      from_as_str.copy(from, length, &my_charset_bin);
 
175
 
 
176
    push_warning_printf(table->in_use, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
177
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
 
178
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
 
179
                          "decimal", from_as_str.c_ptr(), field_name,
 
180
                        (uint32_t) table->in_use->row_count);
 
181
    my_decimal_set_zero(&decimal_value);
 
182
 
 
183
    break;
 
184
    }
 
185
  }
 
186
 
 
187
  store_value(&decimal_value);
 
188
  return(err);
 
189
}
 
190
 
 
191
 
 
192
/**
 
193
  @todo
 
194
  Fix following when double2my_decimal when double2decimal
 
195
  will return E_DEC_TRUNCATED always correctly
 
196
*/
 
197
 
 
198
int Field_new_decimal::store(double nr)
 
199
{
 
200
  my_decimal decimal_value;
 
201
  int err;
 
202
 
 
203
  err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
 
204
                         &decimal_value);
 
205
  if (err)
 
206
  {
 
207
    if (check_overflow(err))
 
208
      set_value_on_overflow(&decimal_value, decimal_value.sign());
 
209
    /* Only issue a warning if store_value doesn't issue an warning */
 
210
    table->in_use->got_warning= 0;
 
211
  }
 
212
  if (store_value(&decimal_value))
 
213
    err= 1;
 
214
  else if (err && !table->in_use->got_warning)
 
215
    err= warn_if_overflow(err);
 
216
  return(err);
 
217
}
 
218
 
 
219
 
 
220
int Field_new_decimal::store(int64_t nr, bool unsigned_val)
 
221
{
 
222
  my_decimal decimal_value;
 
223
  int err;
 
224
 
 
225
  if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
 
226
                           nr, unsigned_val, &decimal_value)))
 
227
  {
 
228
    if (check_overflow(err))
 
229
      set_value_on_overflow(&decimal_value, decimal_value.sign());
 
230
    /* Only issue a warning if store_value doesn't issue an warning */
 
231
    table->in_use->got_warning= 0;
 
232
  }
 
233
  if (store_value(&decimal_value))
 
234
    err= 1;
 
235
  else if (err && !table->in_use->got_warning)
 
236
    err= warn_if_overflow(err);
 
237
  return err;
 
238
}
 
239
 
 
240
 
 
241
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
 
242
{
 
243
  return store_value(decimal_value);
 
244
}
 
245
 
 
246
 
 
247
int Field_new_decimal::store_time(DRIZZLE_TIME *ltime,
 
248
                                  enum enum_drizzle_timestamp_type t_type __attribute__((unused)))
 
249
{
 
250
    my_decimal decimal_value;
 
251
    return store_value(date2my_decimal(ltime, &decimal_value));
 
252
}
 
253
 
 
254
 
 
255
double Field_new_decimal::val_real(void)
 
256
{
 
257
  double dbl;
 
258
  my_decimal decimal_value;
 
259
  my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
 
260
  return dbl;
 
261
}
 
262
 
 
263
 
 
264
int64_t Field_new_decimal::val_int(void)
 
265
{
 
266
  int64_t i;
 
267
  my_decimal decimal_value;
 
268
  my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
 
269
                 unsigned_flag, &i);
 
270
  return i;
 
271
}
 
272
 
 
273
 
 
274
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
 
275
{
 
276
  binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
 
277
                    precision, dec);
 
278
  return(decimal_value);
 
279
}
 
280
 
 
281
 
 
282
String *Field_new_decimal::val_str(String *val_buffer,
 
283
                                   String *val_ptr __attribute__((unused)))
 
284
{
 
285
  my_decimal decimal_value;
 
286
  uint32_t fixed_precision= decimal_precision ? precision : 0;
 
287
  my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
 
288
                    fixed_precision, dec, '0', val_buffer);
 
289
  return val_buffer;
 
290
}
 
291
 
 
292
 
 
293
int Field_new_decimal::cmp(const unsigned char *a,const unsigned char*b)
 
294
{
 
295
  return memcmp(a, b, bin_size);
 
296
}
 
297
 
 
298
 
 
299
void Field_new_decimal::sort_string(unsigned char *buff,
 
300
                                    uint32_t length __attribute__((unused)))
 
301
{
 
302
  memcpy(buff, ptr, bin_size);
 
303
}
 
304
 
 
305
 
 
306
void Field_new_decimal::sql_type(String &str) const
 
307
{
 
308
  const CHARSET_INFO * const cs= str.charset();
 
309
  str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
 
310
                                "decimal(%d,%d)", precision, (int)dec));
 
311
  add_unsigned(str);
 
312
}
 
313
 
 
314
 
 
315
/**
 
316
   Save the field metadata for new decimal fields.
 
317
 
 
318
   Saves the precision in the first byte and decimals() in the second
 
319
   byte of the field metadata array at index of *metadata_ptr and 
 
320
   *(metadata_ptr + 1).
 
321
 
 
322
   @param   metadata_ptr   First byte of field metadata
 
323
 
 
324
   @returns number of bytes written to metadata_ptr
 
325
*/
 
326
int Field_new_decimal::do_save_field_metadata(unsigned char *metadata_ptr)
 
327
{
 
328
  *metadata_ptr= precision;
 
329
  *(metadata_ptr + 1)= decimals();
 
330
  return 2;
 
331
}
 
332
 
 
333
 
 
334
/**
 
335
   Returns the number of bytes field uses in row-based replication 
 
336
   row packed size.
 
337
 
 
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.
 
341
 
 
342
   @param   field_metadata   Encoded size in field metadata
 
343
 
 
344
   @returns The size of the field based on the field metadata.
 
345
*/
 
346
uint32_t Field_new_decimal::pack_length_from_metadata(uint32_t field_metadata)
 
347
{
 
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, 
 
351
                                                     source_decimal);
 
352
  return (source_size);
 
353
}
 
354
 
 
355
 
 
356
/**
 
357
   Check to see if field size is compatible with destination.
 
358
 
 
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). 
 
363
 
 
364
   @param   field_metadata   Encoded size in field metadata
 
365
 
 
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
 
368
*/
 
369
int Field_new_decimal::compatible_field_size(uint32_t field_metadata)
 
370
{
 
371
  int compatible= 0;
 
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, 
 
375
                                                     source_decimal);
 
376
  uint32_t const destination_size= row_pack_length();
 
377
  compatible= (source_size <= destination_size);
 
378
  if (compatible)
 
379
    compatible= (source_precision <= precision) &&
 
380
                (source_decimal <= decimals());
 
381
  return (compatible);
 
382
}
 
383
 
 
384
 
 
385
uint32_t Field_new_decimal::is_equal(Create_field *new_field)
 
386
{
 
387
  return ((new_field->sql_type == real_type()) &&
 
388
          ((new_field->flags & UNSIGNED_FLAG) == 
 
389
           (uint) (flags & UNSIGNED_FLAG)) &&
 
390
          ((new_field->flags & AUTO_INCREMENT_FLAG) ==
 
391
           (uint) (flags & AUTO_INCREMENT_FLAG)) &&
 
392
          (new_field->length == max_display_length()) &&
 
393
          (new_field->decimals == dec));
 
394
}
 
395
 
 
396
 
 
397
/**
 
398
   Unpack a decimal field from row data.
 
399
 
 
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.
 
402
  
 
403
   @param   to         Destination of the data
 
404
   @param   from       Source of the data
 
405
   @param   param_data Precision (upper) and decimal (lower) values
 
406
 
 
407
   @return  New pointer into memory based on from + length of the data
 
408
*/
 
409
const unsigned char *
 
410
Field_new_decimal::unpack(unsigned char* to,
 
411
                          const unsigned char *from,
 
412
                          uint32_t param_data,
 
413
                          bool low_byte_first)
 
414
{
 
415
  if (param_data == 0)
 
416
    return Field::unpack(to, from, param_data, low_byte_first);
 
417
 
 
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()))
 
427
  {
 
428
    /*
 
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.
 
432
    */
 
433
    decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
 
434
    decimal_t dec;
 
435
    dec.len= from_precision;
 
436
    dec.buf= dec_buf;
 
437
    /*
 
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.
 
441
    */
 
442
    bin2decimal((unsigned char *)from, &dec, from_precision, from_decimal);
 
443
    decimal2bin(&dec, to, precision, decimals());
 
444
  }
 
445
  else
 
446
    memcpy(to, from, len); // Sizes are the same, just copy the data.
 
447
  return from+len;
 
448
}
 
449