~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mystrings/decimal.h

  • Committer: Jay Pipes
  • Date: 2009-01-30 04:01:12 UTC
  • mto: This revision was merged to the branch mainline in revision 830.
  • Revision ID: jpipes@serialcoder-20090130040112-svbn774guj98pwi4
To remain in compatibility with MySQL, added ability to interpret
decimal arguments as datetime strings for temporal functions.

Fixed YEAR(), MONTH(), DAYOFMONTH(), DAYOFYEAR(), HOUR(), MINUTE(), SECOND(), and MICROSECOND()
to accept decimal parameters and interpret them the same way as MySQL.

Fixed an issue with the TemporalFormat::matches() method which was 
incorrectly assuming all microsecond arguments were specified as 6 digits.
Added power of 10 multiplier to usecond calculation. This fixes issues with
failures in type_date and func_sapdb test cases.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
#ifndef DRIZZLED_TYPE_DECIMAL_H
17
 
#define DRIZZLED_TYPE_DECIMAL_H
18
 
#include <assert.h>
19
 
#include <drizzled/sql_string.h>
20
 
#include "drizzled/definitions.h"
21
 
#include "drizzled/type/time.h"
22
 
namespace drizzled
23
 
{
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#ifndef _decimal_h
 
17
#define _decimal_h
 
18
 
 
19
#if defined(__cplusplus)
 
20
extern "C" {
 
21
#endif
24
22
 
25
23
typedef enum
26
 
{
27
 
  TRUNCATE= 0,
28
 
  HALF_EVEN,
29
 
  HALF_UP,
30
 
  CEILING,
31
 
  FLOOR
32
 
} decimal_round_mode;
 
24
{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR}
 
25
  decimal_round_mode;
33
26
typedef int32_t decimal_digit_t;
34
27
 
35
 
struct decimal_t {
 
28
typedef struct st_decimal_t {
36
29
  int    intg, frac, len;
37
30
  bool sign;
38
31
  decimal_digit_t *buf;
39
 
 
40
 
  /* set a decimal_t to zero */
41
 
  inline void set_zero()
42
 
  {                                                         
43
 
    buf[0]= 0;
44
 
    intg= 1;
45
 
    frac= 0;
46
 
    sign= 0; 
47
 
  }
48
 
 
49
 
  /* negate a decimal */
50
 
  inline void negate()
51
 
  {
52
 
    sign^=1;
53
 
  }
54
 
 
55
 
  int isZero() const;
56
 
 
57
 
};
 
32
} decimal_t;
58
33
 
59
34
int internal_str2dec(char *from, decimal_t *to, char **end,
60
35
                     bool fixed);
61
 
int decimal2string(const decimal_t *from, char *to, int *to_len,
 
36
int decimal2string(decimal_t *from, char *to, int *to_len,
62
37
                   int fixed_precision, int fixed_decimals,
63
38
                   char filler);
64
 
int decimal2uint64_t(const decimal_t *from, uint64_t *to);
65
 
int uint64_t2decimal(const uint64_t from, decimal_t *to);
66
 
int decimal2int64_t(const decimal_t *from, int64_t *to);
67
 
int int64_t2decimal(const int64_t from, decimal_t *to);
68
 
int decimal2double(const decimal_t *from, double *to);
69
 
int double2decimal(const double from, decimal_t *to);
 
39
int decimal2uint64_t(decimal_t *from, uint64_t *to);
 
40
int uint64_t2decimal(uint64_t from, decimal_t *to);
 
41
int decimal2int64_t(decimal_t *from, int64_t *to);
 
42
int int64_t2decimal(int64_t from, decimal_t *to);
 
43
int decimal2double(decimal_t *from, double *to);
 
44
int double2decimal(double from, decimal_t *to);
70
45
int decimal_actual_fraction(decimal_t *from);
71
 
int decimal2bin(const decimal_t *from, unsigned char *to, int precision, int scale);
 
46
int decimal2bin(decimal_t *from, unsigned char *to, int precision, int scale);
72
47
int bin2decimal(const unsigned char *from, decimal_t *to, int precision, int scale);
73
48
 
 
49
int decimal_size(int precision, int scale);
74
50
int decimal_bin_size(int precision, int scale);
 
51
int decimal_result_size(decimal_t *from1, decimal_t *from2, char op,
 
52
                        int param);
75
53
 
76
 
int decimal_intg(const decimal_t *from);
77
 
int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to);
78
 
int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to);
79
 
int decimal_cmp(const decimal_t *from1, const decimal_t *from2);
80
 
int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to);
81
 
int decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to,
 
54
int decimal_intg(decimal_t *from);
 
55
int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to);
 
56
int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to);
 
57
int decimal_cmp(decimal_t *from1, decimal_t *from2);
 
58
int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to);
 
59
int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to,
82
60
                int scale_incr);
83
 
int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to);
84
 
int decimal_round(const decimal_t *from, decimal_t *to, int new_scale,
 
61
int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to);
 
62
int decimal_round(decimal_t *from, decimal_t *to, int new_scale,
85
63
                  decimal_round_mode mode);
 
64
int decimal_is_zero(decimal_t *from);
86
65
void max_decimal(int precision, int frac, decimal_t *to);
87
66
 
88
 
inline int string2decimal(char *from, decimal_t *to, char **end)
89
 
{
90
 
  return internal_str2dec(from, to, end, false);
91
 
}
 
67
#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0)
 
68
#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1)
 
69
 
 
70
/* set a decimal_t to zero */
 
71
 
 
72
#define decimal_make_zero(dec)        do {                \
 
73
                                        (dec)->buf[0]=0;    \
 
74
                                        (dec)->intg=1;      \
 
75
                                        (dec)->frac=0;      \
 
76
                                        (dec)->sign=0;      \
 
77
                                      } while(0)
92
78
 
93
79
/*
94
80
  returns the length of the buffer to hold string representation
95
81
  of the decimal (including decimal dot, possible sign and \0)
96
82
*/
97
83
 
98
 
inline int decimal_string_size(const decimal_t *dec)
99
 
{
100
 
  return (dec->intg ? dec->intg : 1) + dec->frac + (dec->frac > 0) + 2;
101
 
}
 
84
#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \
 
85
                                  (dec)->frac + ((dec)->frac > 0) + 2)
 
86
 
 
87
/* negate a decimal */
 
88
#define decimal_neg(dec) do { (dec)->sign^=1; } while(0)
102
89
 
103
90
/*
104
91
  conventions:
120
107
#define E_DEC_ERROR            31
121
108
#define E_DEC_FATAL_ERROR      30
122
109
 
123
 
 
124
 
#define DECIMAL_LONGLONG_DIGITS 22
125
 
#define DECIMAL_LONG_DIGITS 10
126
 
#define DECIMAL_LONG3_DIGITS 8
127
 
 
128
 
/** maximum length of buffer in our big digits (uint32_t). */
129
 
#define DECIMAL_BUFF_LENGTH 9
130
 
 
131
 
/* the number of digits that type::Decimal can possibly contain */
132
 
#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
133
 
 
134
 
 
135
 
/**
136
 
  maximum guaranteed precision of number in decimal digits (number of our
137
 
  digits * number of decimal digits in one our big digit - number of decimal
138
 
  digits in one our big digit decreased by 1 (because we always put decimal
139
 
  point on the border of our big digits))
140
 
*/
141
 
#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
142
 
#define DECIMAL_MAX_SCALE 30
143
 
#define DECIMAL_NOT_SPECIFIED 31
144
 
 
145
 
/**
146
 
  maximum length of string representation (number of maximum decimal
147
 
  digits + 1 position for sign + 1 position for decimal point)
148
 
*/
149
 
#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
150
 
 
151
 
/**
152
 
  maximum size of packet length.
153
 
*/
154
 
#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION
155
 
 
156
 
namespace type {
157
 
class Decimal;
158
 
}
159
 
 
160
 
inline int class_decimal_int_part(uint32_t precision, uint32_t decimals)
161
 
{
162
 
  return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
163
 
}
164
 
 
165
 
int decimal_operation_results(int result);
166
 
 
167
 
inline void max_Decimal(type::Decimal *to, int precision, int frac)
168
 
{
169
 
  assert((precision <= DECIMAL_MAX_PRECISION)&&
170
 
              (frac <= DECIMAL_MAX_SCALE));
171
 
  max_decimal(precision, frac, (decimal_t*) to);
172
 
}
173
 
 
174
 
inline void max_internal_decimal(type::Decimal *to)
175
 
{
176
 
  max_Decimal(to, DECIMAL_MAX_PRECISION, 0);
177
 
}
178
 
 
179
 
inline int check_result(uint32_t mask, int result)
180
 
{
181
 
  if (result & mask)
182
 
    decimal_operation_results(result);
183
 
  return result;
184
 
}
185
 
 
186
 
namespace type {
187
 
/**
188
 
  type Decimal class limits 'decimal_t' type to what we need in MySQL.
189
 
 
190
 
  It contains internally all necessary space needed by the instance so
191
 
  no extra memory is needed. One should call fix_buffer_pointer() function
192
 
  when he moves type::Decimal objects in memory.
193
 
*/
194
 
 
195
 
class Decimal : public decimal_t
196
 
{
197
 
  decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
198
 
 
199
 
public:
200
 
 
201
 
  void init()
202
 
  {
203
 
    len= DECIMAL_BUFF_LENGTH;
204
 
    buf= buffer;
205
 
#if !defined (HAVE_VALGRIND)
206
 
    /* Set buffer to 'random' value to find wrong buffer usage */
207
 
    for (uint32_t i= 0; i < DECIMAL_BUFF_LENGTH; i++)
208
 
      buffer[i]= i;
209
 
#endif
210
 
  }
211
 
 
212
 
  Decimal()
213
 
  {
214
 
    init();
215
 
  }
216
 
 
217
 
  void fix_buffer_pointer() { buf= buffer; }
218
 
  bool sign() const { return decimal_t::sign; }
219
 
  void sign(bool s) { decimal_t::sign= s; }
220
 
  uint32_t precision() const { return intg + frac; }
221
 
 
222
 
  int val_int32(uint32_t mask, bool unsigned_flag, int64_t *l) const
223
 
  {
224
 
    type::Decimal rounded;
225
 
    /* decimal_round can return only E_DEC_TRUNCATED */
226
 
    decimal_round(static_cast<const decimal_t*>(this), &rounded, 0, HALF_UP);
227
 
    return check_result(mask, (unsigned_flag ?
228
 
                               decimal2uint64_t(&rounded, reinterpret_cast<uint64_t *>(l)) :
229
 
                               decimal2int64_t(&rounded, l)));
230
 
  }
231
 
 
232
 
  int string_length() const
233
 
  {
234
 
    return decimal_string_size(this);
235
 
  }
236
 
 
237
 
  int val_binary(uint32_t mask, unsigned char *bin, int prec, int scale) const;
238
 
 
239
 
  int store(uint32_t mask, const char *from, uint32_t length, const CHARSET_INFO * charset);
240
 
 
241
 
  int store(uint32_t mask, char *str, char **end)
242
 
  {
243
 
    return check_result_and_overflow(mask, string2decimal(str, static_cast<decimal_t*>(this), end));
244
 
  }
245
 
 
246
 
  int store(uint32_t mask, const String *str)
247
 
  {
248
 
    return store(mask, str->ptr(), str->length(), str->charset());
249
 
  }
250
 
 
251
 
  int check_result_and_overflow(uint32_t mask, int result)
252
 
  {
253
 
    if (check_result(mask, result) & E_DEC_OVERFLOW)
254
 
    {
255
 
      bool _sign= sign();
256
 
      fix_buffer_pointer();
257
 
      max_internal_decimal(this);
258
 
      sign(_sign);
259
 
    }
260
 
    return result;
261
 
  }
262
 
 
263
 
  void convert(double &value) const;
264
 
};
265
 
 
266
 
} // type
267
 
 
268
 
std::ostream& operator<<(std::ostream& output, const type::Decimal &dec);
269
 
 
270
 
inline uint32_t class_decimal_length_to_precision(uint32_t length, uint32_t scale,
271
 
                                                  bool unsigned_flag)
272
 
{
273
 
  return (uint32_t) (length - (scale>0 ? 1:0) - (unsigned_flag ? 0:1));
274
 
}
275
 
 
276
 
inline uint32_t class_decimal_precision_to_length(uint32_t precision, uint8_t scale,
277
 
                                                  bool unsigned_flag)
278
 
{
279
 
  set_if_smaller(precision, (uint32_t)DECIMAL_MAX_PRECISION);
280
 
  return static_cast<uint32_t>(precision + (scale>0 ? 1:0) + (unsigned_flag ? 0:1));
281
 
}
282
 
 
283
 
 
284
 
inline
285
 
int class_decimal_max_length(const type::Decimal *d)
286
 
{
287
 
  /* -1 because we do not count \0 */
288
 
  return decimal_string_size(d) - 1;
289
 
}
290
 
 
291
 
 
292
 
inline
293
 
int class_decimal_get_binary_size(uint32_t precision, uint32_t scale)
294
 
{
295
 
  return decimal_bin_size(static_cast<int>(precision), static_cast<int>(scale));
296
 
}
297
 
 
298
 
 
299
 
inline
300
 
void class_decimal2decimal(const type::Decimal *from, type::Decimal *to)
301
 
{
302
 
  *to= *from;
303
 
  to->fix_buffer_pointer();
304
 
}
305
 
 
306
 
 
307
 
inline
308
 
int binary2_class_decimal(uint32_t mask, const unsigned char *bin, type::Decimal *d, int prec,
309
 
                      int scale)
310
 
{
311
 
  return check_result(mask, bin2decimal(bin, static_cast<decimal_t*>(d), prec, scale));
312
 
}
313
 
 
314
 
 
315
 
inline
316
 
int class_decimal_round(uint32_t mask, const type::Decimal *from, int scale,
317
 
                     bool truncate, type::Decimal *to)
318
 
{
319
 
  return check_result(mask, decimal_round(static_cast<const decimal_t*>(from), to, scale,
320
 
                                          (truncate ? TRUNCATE : HALF_UP)));
321
 
}
322
 
 
323
 
 
324
 
inline
325
 
int class_decimal_floor(uint32_t mask, const type::Decimal *from, type::Decimal *to)
326
 
{
327
 
  return check_result(mask, decimal_round(static_cast<const decimal_t*>(from), to, 0, FLOOR));
328
 
}
329
 
 
330
 
 
331
 
inline
332
 
int class_decimal_ceiling(uint32_t mask, const type::Decimal *from, type::Decimal *to)
333
 
{
334
 
  return check_result(mask, decimal_round(static_cast<const decimal_t*>(from), to, 0, CEILING));
335
 
}
336
 
 
337
 
 
338
 
int class_decimal2string(const type::Decimal *d,
339
 
                         uint32_t fixed_dec, String *str);
340
 
 
341
 
 
342
 
inline
343
 
int class_decimal2double(uint32_t, const type::Decimal *d, double *result)
344
 
{
345
 
  /* No need to call check_result as this will always succeed */
346
 
  return decimal2double(static_cast<const decimal_t*>(d), result);
347
 
}
348
 
 
349
 
 
350
 
type::Decimal *date2_class_decimal(type::Time *ltime, type::Decimal *dec);
351
 
 
352
 
 
353
 
inline
354
 
int double2_class_decimal(uint32_t mask, double val, type::Decimal *d)
355
 
{
356
 
  return d->check_result_and_overflow(mask, double2decimal(val, static_cast<decimal_t*>(d)));
357
 
}
358
 
 
359
 
 
360
 
inline
361
 
int int2_class_decimal(uint32_t mask, int64_t i, bool unsigned_flag, type::Decimal *d)
362
 
{
363
 
  return check_result(mask, (unsigned_flag ?
364
 
                             uint64_t2decimal(static_cast<uint64_t>(i), d) :
365
 
                             int64_t2decimal(i, d)));
366
 
}
367
 
 
368
 
 
369
 
inline
370
 
void class_decimal_neg(decimal_t *arg)
371
 
{
372
 
  if (arg->isZero())
373
 
  {
374
 
    arg->sign= 0;
375
 
    return;
376
 
  }
377
 
  arg->negate();
378
 
}
379
 
 
380
 
 
381
 
inline
382
 
int class_decimal_add(uint32_t mask, type::Decimal *res, const type::Decimal *a,
383
 
                   const type::Decimal *b)
384
 
{
385
 
  return res->check_result_and_overflow(mask,
386
 
                                        decimal_add(static_cast<const decimal_t*>(a),
387
 
                                                    static_cast<const decimal_t*>(b), res));
388
 
}
389
 
 
390
 
 
391
 
inline
392
 
int class_decimal_sub(uint32_t mask, type::Decimal *res, const type::Decimal *a,
393
 
                   const type::Decimal *b)
394
 
{
395
 
  return res->check_result_and_overflow(mask,
396
 
                                        decimal_sub(static_cast<const decimal_t*>(a),
397
 
                                                    static_cast<const decimal_t*>(b), res));
398
 
}
399
 
 
400
 
 
401
 
inline
402
 
int class_decimal_mul(uint32_t mask, type::Decimal *res, const type::Decimal *a,
403
 
                   const type::Decimal *b)
404
 
{
405
 
  return res->check_result_and_overflow(mask,
406
 
                                        decimal_mul(static_cast<const decimal_t*>(a),
407
 
                                                    static_cast<const decimal_t*>(b),res));
408
 
}
409
 
 
410
 
 
411
 
inline
412
 
int class_decimal_div(uint32_t mask, type::Decimal *res, const type::Decimal *a,
413
 
                   const type::Decimal *b, int div_scale_inc)
414
 
{
415
 
  return res->check_result_and_overflow(mask,
416
 
                                        decimal_div(static_cast<const decimal_t*>(a),
417
 
                                                    static_cast<const decimal_t*>(b),res,
418
 
                                                    div_scale_inc));
419
 
}
420
 
 
421
 
 
422
 
inline
423
 
int class_decimal_mod(uint32_t mask, type::Decimal *res, const type::Decimal *a,
424
 
                   const type::Decimal *b)
425
 
{
426
 
  return res->check_result_and_overflow(mask,
427
 
                                        decimal_mod(static_cast<const decimal_t*>(a),
428
 
                                                    static_cast<const decimal_t*>(b),res));
429
 
}
430
 
 
431
 
 
432
 
/**
433
 
  @return
434
 
    -1 if a<b, 1 if a>b and 0 if a==b
435
 
*/
436
 
inline
437
 
int class_decimal_cmp(const type::Decimal *a, const type::Decimal *b)
438
 
{
439
 
  return decimal_cmp(static_cast<const decimal_t*>(a),
440
 
                     static_cast<const decimal_t*>(b));
441
 
}
442
 
 
443
 
 
444
 
inline
445
 
int class_decimal_intg(const type::Decimal *a)
446
 
{
447
 
  return decimal_intg(static_cast<const decimal_t*>(a));
448
 
}
449
 
 
450
 
 
451
 
void class_decimal_trim(uint32_t *precision, uint32_t *scale);
452
 
 
453
 
inline type::Decimal &decimal_zero_const()
454
 
{
455
 
  static type::Decimal _decimal_zero;
456
 
  return _decimal_zero;
457
 
}
458
 
 
459
 
double my_double_round(double value, int64_t dec, bool dec_unsigned,
460
 
                       bool truncate);
461
 
 
462
 
 
463
 
#define decimal_zero decimal_zero_const()
464
 
 
465
 
} /* namespace drizzled */
466
 
 
467
 
#endif /* DRIZZLED_TYPE_DECIMAL_H */
 
110
#if defined(__cplusplus)
 
111
}
 
112
#endif
 
113
 
 
114
#endif
468
115