~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/fdecimal.cc

  • Committer: Brian Aker
  • Date: 2008-07-14 22:18:37 UTC
  • mfrom: (77.1.96 codestyle)
  • Revision ID: brian@tangent.org-20080714221837-oceoshx7fjkla9u3
Merge from Monty

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(DRIZZLE_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