~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/fdecimal.cc

Merged build changes from Antony.

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/field/fdecimal.h>
 
26
 
 
27
/****************************************************************************
 
28
** Field_new_decimal
 
29
****************************************************************************/
 
30
 
 
31
Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
 
32
                                     uint32_t len_arg, uchar *null_ptr_arg,
 
33
                                     uchar null_bit_arg,
 
34
                                     enum utype unireg_check_arg,
 
35
                                     const char *field_name_arg,
 
36
                                     uint8_t dec_arg,bool zero_arg,
 
37
                                     bool unsigned_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)
 
40
{
 
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);
 
46
}
 
47
 
 
48
 
 
49
Field_new_decimal::Field_new_decimal(uint32_t len_arg,
 
50
                                     bool maybe_null_arg,
 
51
                                     const char *name,
 
52
                                     uint8_t dec_arg,
 
53
                                     bool unsigned_arg)
 
54
  :Field_num((uchar*) 0, len_arg,
 
55
             maybe_null_arg ? (uchar*) "": 0, 0,
 
56
             NONE, name, dec_arg, 0, unsigned_arg)
 
57
{
 
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);
 
63
}
 
64
 
 
65
 
 
66
int Field_new_decimal::reset(void)
 
67
{
 
68
  store_value(&decimal_zero);
 
69
  return 0;
 
70
}
 
71
 
 
72
 
 
73
/**
 
74
  Generate max/min decimal value in case of overflow.
 
75
 
 
76
  @param decimal_value     buffer for value
 
77
  @param sign              sign of value which caused overflow
 
78
*/
 
79
 
 
80
void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
 
81
                                              bool sign)
 
82
{
 
83
  max_my_decimal(decimal_value, precision, decimals());
 
84
  if (sign)
 
85
  {
 
86
    if (unsigned_flag)
 
87
      my_decimal_set_zero(decimal_value);
 
88
    else
 
89
      decimal_value->sign(true);
 
90
  }
 
91
  return;
 
92
}
 
93
 
 
94
 
 
95
/**
 
96
  Store decimal value in the binary buffer.
 
97
 
 
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.
 
101
 
 
102
  @param decimal_value   my_decimal
 
103
 
 
104
  @retval
 
105
    0 ok
 
106
  @retval
 
107
    1 error
 
108
*/
 
109
 
 
110
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
 
111
{
 
112
  int error= 0;
 
113
 
 
114
  /* check that we do not try to write negative value in unsigned field */
 
115
  if (unsigned_flag && decimal_value->sign())
 
116
  {
 
117
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
 
118
    error= 1;
 
119
    decimal_value= &decimal_zero;
 
120
  }
 
121
 
 
122
  if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
 
123
                                         decimal_value, ptr, precision, dec)))
 
124
  {
 
125
    my_decimal buff;
 
126
    set_value_on_overflow(&buff, decimal_value->sign());
 
127
    my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
 
128
    error= 1;
 
129
  }
 
130
  return(error);
 
131
}
 
132
 
 
133
 
 
134
int Field_new_decimal::store(const char *from, uint length,
 
135
                             CHARSET_INFO *charset_arg)
 
136
{
 
137
  int err;
 
138
  my_decimal decimal_value;
 
139
 
 
140
  if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
 
141
                           ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
 
142
                           from, length, charset_arg,
 
143
                           &decimal_value)) &&
 
144
      table->in_use->abort_on_warning)
 
145
  {
 
146
    /* Because "from" is not NUL-terminated and we use %s in the ER() */
 
147
    String from_as_str;
 
148
    from_as_str.copy(from, length, &my_charset_bin);
 
149
 
 
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);
 
155
 
 
156
    return(err);
 
157
  }
 
158
 
 
159
  switch (err) {
 
160
  case E_DEC_TRUNCATED:
 
161
    set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DATA_TRUNCATED, 1);
 
162
    break;
 
163
  case E_DEC_OVERFLOW:
 
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());
 
166
    break;
 
167
  case E_DEC_BAD_NUM:
 
168
    {
 
169
      /* Because "from" is not NUL-terminated and we use %s in the ER() */
 
170
      String from_as_str;
 
171
      from_as_str.copy(from, length, &my_charset_bin);
 
172
 
 
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);
 
179
 
 
180
    break;
 
181
    }
 
182
  }
 
183
 
 
184
  store_value(&decimal_value);
 
185
  return(err);
 
186
}
 
187
 
 
188
 
 
189
/**
 
190
  @todo
 
191
  Fix following when double2my_decimal when double2decimal
 
192
  will return E_DEC_TRUNCATED always correctly
 
193
*/
 
194
 
 
195
int Field_new_decimal::store(double nr)
 
196
{
 
197
  my_decimal decimal_value;
 
198
  int err;
 
199
 
 
200
  err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
 
201
                         &decimal_value);
 
202
  if (err)
 
203
  {
 
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;
 
208
  }
 
209
  if (store_value(&decimal_value))
 
210
    err= 1;
 
211
  else if (err && !table->in_use->got_warning)
 
212
    err= warn_if_overflow(err);
 
213
  return(err);
 
214
}
 
215
 
 
216
 
 
217
int Field_new_decimal::store(int64_t nr, bool unsigned_val)
 
218
{
 
219
  my_decimal decimal_value;
 
220
  int err;
 
221
 
 
222
  if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
 
223
                           nr, unsigned_val, &decimal_value)))
 
224
  {
 
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;
 
229
  }
 
230
  if (store_value(&decimal_value))
 
231
    err= 1;
 
232
  else if (err && !table->in_use->got_warning)
 
233
    err= warn_if_overflow(err);
 
234
  return err;
 
235
}
 
236
 
 
237
 
 
238
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
 
239
{
 
240
  return store_value(decimal_value);
 
241
}
 
242
 
 
243
 
 
244
int Field_new_decimal::store_time(MYSQL_TIME *ltime,
 
245
                                  timestamp_type t_type __attribute__((unused)))
 
246
{
 
247
    my_decimal decimal_value;
 
248
    return store_value(date2my_decimal(ltime, &decimal_value));
 
249
}
 
250
 
 
251
 
 
252
double Field_new_decimal::val_real(void)
 
253
{
 
254
  double dbl;
 
255
  my_decimal decimal_value;
 
256
  my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
 
257
  return dbl;
 
258
}
 
259
 
 
260
 
 
261
int64_t Field_new_decimal::val_int(void)
 
262
{
 
263
  int64_t i;
 
264
  my_decimal decimal_value;
 
265
  my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
 
266
                 unsigned_flag, &i);
 
267
  return i;
 
268
}
 
269
 
 
270
 
 
271
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
 
272
{
 
273
  binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
 
274
                    precision, dec);
 
275
  return(decimal_value);
 
276
}
 
277
 
 
278
 
 
279
String *Field_new_decimal::val_str(String *val_buffer,
 
280
                                   String *val_ptr __attribute__((unused)))
 
281
{
 
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);
 
286
  return val_buffer;
 
287
}
 
288
 
 
289
 
 
290
int Field_new_decimal::cmp(const uchar *a,const uchar*b)
 
291
{
 
292
  return memcmp(a, b, bin_size);
 
293
}
 
294
 
 
295
 
 
296
void Field_new_decimal::sort_string(uchar *buff,
 
297
                                    uint length __attribute__((unused)))
 
298
{
 
299
  memcpy(buff, ptr, bin_size);
 
300
}
 
301
 
 
302
 
 
303
void Field_new_decimal::sql_type(String &str) const
 
304
{
 
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));
 
308
  add_unsigned(str);
 
309
}
 
310
 
 
311
 
 
312
/**
 
313
   Save the field metadata for new decimal fields.
 
314
 
 
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 
 
317
   *(metadata_ptr + 1).
 
318
 
 
319
   @param   metadata_ptr   First byte of field metadata
 
320
 
 
321
   @returns number of bytes written to metadata_ptr
 
322
*/
 
323
int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr)
 
324
{
 
325
  *metadata_ptr= precision;
 
326
  *(metadata_ptr + 1)= decimals();
 
327
  return 2;
 
328
}
 
329
 
 
330
 
 
331
/**
 
332
   Returns the number of bytes field uses in row-based replication 
 
333
   row packed size.
 
334
 
 
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.
 
338
 
 
339
   @param   field_metadata   Encoded size in field metadata
 
340
 
 
341
   @returns The size of the field based on the field metadata.
 
342
*/
 
343
uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
 
344
{
 
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, 
 
348
                                                     source_decimal);
 
349
  return (source_size);
 
350
}
 
351
 
 
352
 
 
353
/**
 
354
   Check to see if field size is compatible with destination.
 
355
 
 
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). 
 
360
 
 
361
   @param   field_metadata   Encoded size in field metadata
 
362
 
 
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
 
365
*/
 
366
int Field_new_decimal::compatible_field_size(uint field_metadata)
 
367
{
 
368
  int compatible= 0;
 
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, 
 
372
                                                     source_decimal);
 
373
  uint const destination_size= row_pack_length();
 
374
  compatible= (source_size <= destination_size);
 
375
  if (compatible)
 
376
    compatible= (source_precision <= precision) &&
 
377
                (source_decimal <= decimals());
 
378
  return (compatible);
 
379
}
 
380
 
 
381
 
 
382
uint Field_new_decimal::is_equal(Create_field *new_field)
 
383
{
 
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));
 
391
}
 
392
 
 
393
 
 
394
/**
 
395
   Unpack a decimal field from row data.
 
396
 
 
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.
 
399
  
 
400
   @param   to         Destination of the data
 
401
   @param   from       Source of the data
 
402
   @param   param_data Precision (upper) and decimal (lower) values
 
403
 
 
404
   @return  New pointer into memory based on from + length of the data
 
405
*/
 
406
const uchar *
 
407
Field_new_decimal::unpack(uchar* to,
 
408
                          const uchar *from,
 
409
                          uint param_data,
 
410
                          bool low_byte_first)
 
411
{
 
412
  if (param_data == 0)
 
413
    return Field::unpack(to, from, param_data, low_byte_first);
 
414
 
 
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()))
 
424
  {
 
425
    /*
 
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.
 
429
    */
 
430
    decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
 
431
    decimal_t dec;
 
432
    dec.len= from_precision;
 
433
    dec.buf= dec_buf;
 
434
    /*
 
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.
 
438
    */
 
439
    bin2decimal((uchar *)from, &dec, from_precision, from_decimal);
 
440
    decimal2bin(&dec, to, precision, decimals());
 
441
  }
 
442
  else
 
443
    memcpy(to, from, len); // Sizes are the same, just copy the data.
 
444
  return from+len;
 
445
}
 
446