~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/decimal.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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
 
 
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
 
 
28
 
extern my_decimal decimal_zero;
29
 
 
30
 
/****************************************************************************
31
 
 ** File_decimal
32
 
 ****************************************************************************/
33
 
 
34
 
Field_decimal::Field_decimal(unsigned char *ptr_arg,
35
 
                             uint32_t len_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,
40
 
                             uint8_t dec_arg,
41
 
                             bool zero_arg,
42
 
                             bool unsigned_arg)
43
 
:Field_num(ptr_arg,
44
 
           len_arg,
45
 
           null_ptr_arg,
46
 
           null_bit_arg,
47
 
           unireg_check_arg,
48
 
           field_name_arg,
49
 
           dec_arg, zero_arg,
50
 
           unsigned_arg)
51
 
{
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);
57
 
}
58
 
 
59
 
Field_decimal::Field_decimal(uint32_t len_arg,
60
 
                             bool maybe_null_arg,
61
 
                             const char *name,
62
 
                             uint8_t dec_arg,
63
 
                             bool unsigned_arg)
64
 
:Field_num((unsigned char*) 0,
65
 
           len_arg,
66
 
           maybe_null_arg ? (unsigned char*) "": 0,
67
 
           0,
68
 
           NONE,
69
 
           name,
70
 
           dec_arg,
71
 
           0,
72
 
           unsigned_arg)
73
 
{
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);
79
 
}
80
 
 
81
 
 
82
 
int Field_decimal::reset(void)
83
 
{
84
 
  store_value(&decimal_zero);
85
 
  return 0;
86
 
}
87
 
 
88
 
 
89
 
/**
90
 
  Generate max/min decimal value in case of overflow.
91
 
 
92
 
  @param decimal_value     buffer for value
93
 
  @param sign              sign of value which caused overflow
94
 
*/
95
 
 
96
 
void Field_decimal::set_value_on_overflow(my_decimal *decimal_value,
97
 
                                          bool sign)
98
 
{
99
 
  max_my_decimal(decimal_value, precision, decimals());
100
 
  if (sign)
101
 
    decimal_value->sign(true);
102
 
 
103
 
  return;
104
 
}
105
 
 
106
 
 
107
 
/**
108
 
  Store decimal value in the binary buffer.
109
 
 
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.
113
 
 
114
 
  @param decimal_value   my_decimal
115
 
 
116
 
  @retval
117
 
  0 ok
118
 
  @retval
119
 
  1 error
120
 
*/
121
 
 
122
 
bool Field_decimal::store_value(const my_decimal *decimal_value)
123
 
{
124
 
  int error= 0;
125
 
 
126
 
  if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
127
 
                                         decimal_value, ptr, precision, dec)))
128
 
  {
129
 
    my_decimal buff;
130
 
    set_value_on_overflow(&buff, decimal_value->sign());
131
 
    my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
132
 
    error= 1;
133
 
  }
134
 
  return(error);
135
 
}
136
 
 
137
 
 
138
 
int Field_decimal::store(const char *from, uint32_t length,
139
 
                         const CHARSET_INFO * const charset_arg)
140
 
{
141
 
  int err;
142
 
  my_decimal decimal_value;
143
 
 
144
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
145
 
 
146
 
  if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
147
 
                           ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
148
 
                           from, length, charset_arg,
149
 
                           &decimal_value)) &&
150
 
      table->in_use->abort_on_warning)
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(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);
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(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);
186
 
 
187
 
      break;
188
 
    }
189
 
  }
190
 
 
191
 
  store_value(&decimal_value);
192
 
  return(err);
193
 
}
194
 
 
195
 
 
196
 
/**
197
 
  @todo
198
 
  Fix following when double2my_decimal when double2decimal
199
 
  will return E_DEC_TRUNCATED always correctly
200
 
*/
201
 
 
202
 
int Field_decimal::store(double nr)
203
 
{
204
 
  my_decimal decimal_value;
205
 
  int err;
206
 
 
207
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
208
 
 
209
 
  err= double2my_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
 
    table->in_use->got_warning= 0;
217
 
  }
218
 
  if (store_value(&decimal_value))
219
 
    err= 1;
220
 
  else if (err && !table->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
 
  my_decimal decimal_value;
229
 
  int err;
230
 
 
231
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
232
 
 
233
 
  if ((err= int2my_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
 
    table->in_use->got_warning= 0;
240
 
  }
241
 
  if (store_value(&decimal_value))
242
 
    err= 1;
243
 
  else if (err && !table->in_use->got_warning)
244
 
    err= warn_if_overflow(err);
245
 
  return err;
246
 
}
247
 
 
248
 
 
249
 
int Field_decimal::store_decimal(const my_decimal *decimal_value)
250
 
{
251
 
  return store_value(decimal_value);
252
 
}
253
 
 
254
 
 
255
 
int Field_decimal::store_time(DRIZZLE_TIME *ltime,
256
 
                              enum enum_drizzle_timestamp_type )
257
 
{
258
 
  my_decimal decimal_value;
259
 
  return store_value(date2my_decimal(ltime, &decimal_value));
260
 
}
261
 
 
262
 
 
263
 
double Field_decimal::val_real(void)
264
 
{
265
 
  double dbl;
266
 
  my_decimal decimal_value;
267
 
 
268
 
  ASSERT_COLUMN_MARKED_FOR_READ;
269
 
 
270
 
  my_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)
277
 
{
278
 
  int64_t i;
279
 
  my_decimal decimal_value;
280
 
 
281
 
  ASSERT_COLUMN_MARKED_FOR_READ;
282
 
 
283
 
  my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), false, &i);
284
 
 
285
 
  return i;
286
 
}
287
 
 
288
 
 
289
 
my_decimal* Field_decimal::val_decimal(my_decimal *decimal_value)
290
 
{
291
 
  ASSERT_COLUMN_MARKED_FOR_READ;
292
 
 
293
 
  binary2my_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,
300
 
                               String *)
301
 
{
302
 
  my_decimal decimal_value;
303
 
 
304
 
  ASSERT_COLUMN_MARKED_FOR_READ;
305
 
 
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);
309
 
  return val_buffer;
310
 
}
311
 
 
312
 
 
313
 
int Field_decimal::cmp(const unsigned char *a,const unsigned char*b)
314
 
{
315
 
  return memcmp(a, b, bin_size);
316
 
}
317
 
 
318
 
 
319
 
void Field_decimal::sort_string(unsigned char *buff,
320
 
                                uint32_t )
321
 
{
322
 
  memcpy(buff, ptr, bin_size);
323
 
}
324
 
 
325
 
 
326
 
void Field_decimal::sql_type(String &str) const
327
 
{
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));
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_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_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_decimal::is_equal(CreateField *new_field_ptr)
386
 
{
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));
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_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 conv_dec;
435
 
    conv_dec.len= from_precision;
436
 
    conv_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, &conv_dec, from_precision, from_decimal);
443
 
    decimal2bin(&conv_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