my_decimal.h 10.9 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2005-2006 MySQL AB
unknown's avatar
unknown committed
2 3 4

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  It is interface module to fixed precision decimals library.

  Most functions use 'uint mask' as parameter, if during operation error
  which fit in this mask is detected then it will be processed automatically
  here. (errors are E_DEC_* constants, see include/decimal.h)

  Most function are just inline wrappers around library calls
*/

#ifndef my_decimal_h
#define my_decimal_h

C_MODE_START
#include <decimal.h>
C_MODE_END

#define DECIMAL_LONGLONG_DIGITS 22
#define DECIMAL_LONG_DIGITS 10
#define DECIMAL_LONG3_DIGITS 8

/* maximum length of buffer in our big digits (uint32) */
unknown's avatar
unknown committed
38
#define DECIMAL_BUFF_LENGTH 9
39 40 41 42

/* the number of digits that my_decimal can possibly contain */
#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)

unknown's avatar
unknown committed
43
/*
unknown's avatar
unknown committed
44
  maximum guaranteed precision of number in decimal digits (number of our
unknown's avatar
unknown committed
45
  digits * number of decimal digits in one our big digit - number of decimal
46
  digits in one our big digit decreased by 1 (because we always put decimal
unknown's avatar
unknown committed
47 48
  point on the border of our big digits))
*/
49
#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
unknown's avatar
unknown committed
50 51 52
#define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31

unknown's avatar
unknown committed
53 54 55 56
/*
  maximum length of string representation (number of maximum decimal
  digits + 1 position for sign + 1 position for decimal point)
*/
57
#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
unknown's avatar
unknown committed
58 59 60
/*
  maximum size of packet length
*/
unknown's avatar
unknown committed
61
#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION
unknown's avatar
unknown committed
62 63 64 65 66 67 68 69 70 71 72 73


inline uint my_decimal_size(uint precision, uint scale)
{
  /*
    Always allocate more space to allow library to put decimal point
    where it want
  */
  return decimal_size(precision, scale) + 1;
}


unknown's avatar
unknown committed
74 75 76 77 78 79
inline int my_decimal_int_part(uint precision, uint decimals)
{
  return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
}


80
/*
81
  my_decimal class limits 'decimal_t' type to what we need in MySQL
82 83 84 85 86
  It contains internally all necessary space needed by the instance so
  no extra memory is needed. One should call fix_buffer_pointer() function
  when he moves my_decimal objects in memory
*/

87
class my_decimal :public decimal_t
unknown's avatar
unknown committed
88
{
89
  decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
unknown's avatar
unknown committed
90 91 92 93 94 95 96

public:

  void init()
  {
    len= DECIMAL_BUFF_LENGTH;
    buf= buffer;
97
#if !defined (HAVE_purify) && !defined(DBUG_OFF)
98
    /* Set buffer to 'random' value to find wrong buffer usage */
unknown's avatar
unknown committed
99 100 101 102 103 104 105 106 107 108
    for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
      buffer[i]= i;
#endif
  }
  my_decimal()
  {
    init();
  }
  void fix_buffer_pointer() { buf= buffer; }

109 110
  bool sign() const { return decimal_t::sign; }
  void sign(bool s) { decimal_t::sign= s; }
unknown's avatar
unknown committed
111
  uint precision() const { return intg + frac; }
unknown's avatar
unknown committed
112 113 114 115 116 117
};


#ifndef DBUG_OFF
void print_decimal(const my_decimal *dec);
void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length);
unknown's avatar
unknown committed
118
const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
119
#else
unknown's avatar
unknown committed
120
#define dbug_decimal_as_string(A) NULL
unknown's avatar
unknown committed
121 122 123 124 125 126 127 128 129 130 131
#endif

#ifndef MYSQL_CLIENT
int decimal_operation_results(int result);
#else
inline int decimal_operation_results(int result)
{
  return result;
}
#endif /*MYSQL_CLIENT*/

132 133 134 135 136 137 138 139 140 141 142 143 144
inline
void max_my_decimal(my_decimal *to, int precision, int frac)
{
  DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&&
              (frac <= DECIMAL_MAX_SCALE));
  max_decimal(precision, frac, (decimal_t*) to);
}

inline void max_internal_decimal(my_decimal *to)
{
  max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
}

unknown's avatar
unknown committed
145 146 147 148 149 150 151
inline int check_result(uint mask, int result)
{
  if (result & mask)
    decimal_operation_results(result);
  return result;
}

152 153 154 155 156 157 158 159 160 161 162 163
inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
{
  if (check_result(mask, result) & E_DEC_OVERFLOW)
  {
    bool sign= val->sign();
    val->fix_buffer_pointer();
    max_internal_decimal(val);
    val->sign(sign);
  }
  return result;
}

unknown's avatar
unknown committed
164 165 166
inline uint my_decimal_length_to_precision(uint length, uint scale,
                                           bool unsigned_flag)
{
167 168 169 170
  /* Precision can't be negative thus ignore unsigned_flag when length is 0. */
  DBUG_ASSERT(length || !scale);
  return (uint) (length - (scale>0 ? 1:0) -
                 (unsigned_flag || !length ? 0:1));
unknown's avatar
unknown committed
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185
inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
                                                           uint8 scale,
                                                           bool unsigned_flag)
{
  /*
    When precision is 0 it means that original length was also 0. Thus
    unsigned_flag is ignored in this case.
  */
  DBUG_ASSERT(precision || !scale);
  return (uint32)(precision + (scale > 0 ? 1 : 0) +
                  (unsigned_flag || !precision ? 0 : 1));
}

unknown's avatar
unknown committed
186 187 188
inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
                                             bool unsigned_flag)
{
189 190 191 192 193
  /*
    When precision is 0 it means that original length was also 0. Thus
    unsigned_flag is ignored in this case.
  */
  DBUG_ASSERT(precision || !scale);
unknown's avatar
unknown committed
194
  set_if_smaller(precision, DECIMAL_MAX_PRECISION);
195 196
  return my_decimal_precision_to_length_no_truncation(precision, scale,
                                                      unsigned_flag);
unknown's avatar
unknown committed
197
}
unknown's avatar
unknown committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

inline
int my_decimal_string_length(const my_decimal *d)
{
  return decimal_string_size(d);
}


inline
int my_decimal_max_length(const my_decimal *d)
{
  /* -1 because we do not count \0 */
  return decimal_string_size(d) - 1;
}


inline
int my_decimal_get_binary_size(uint precision, uint scale)
{
  return decimal_bin_size((int)precision, (int)scale);
}


inline
void my_decimal2decimal(const my_decimal *from, my_decimal *to)
{
  *to= *from;
  to->fix_buffer_pointer();
}


229
int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
unknown's avatar
unknown committed
230 231 232 233
		      int scale);


inline
234
int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec,
unknown's avatar
unknown committed
235 236
		      int scale)
{
237
  return check_result(mask, bin2decimal((char *)bin, (decimal_t*) d, prec,
unknown's avatar
unknown committed
238 239 240 241 242 243 244
					scale));
}


inline
int my_decimal_set_zero(my_decimal *d)
{
245
  decimal_make_zero(((decimal_t*) d));
unknown's avatar
unknown committed
246 247 248 249 250 251 252
  return 0;
}


inline
bool my_decimal_is_zero(const my_decimal *decimal_value)
{
253
  return decimal_is_zero((decimal_t*) decimal_value);
unknown's avatar
unknown committed
254 255 256 257 258 259 260
}


inline
int my_decimal_round(uint mask, const my_decimal *from, int scale,
                     bool truncate, my_decimal *to)
{
261
  return check_result(mask, decimal_round((decimal_t*) from, to, scale,
unknown's avatar
unknown committed
262 263 264 265 266 267 268
					  (truncate ? TRUNCATE : HALF_UP)));
}


inline
int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
{
269
  return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR));
unknown's avatar
unknown committed
270 271 272 273 274 275
}


inline
int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
{
276
  return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING));
unknown's avatar
unknown committed
277 278 279 280
}


#ifndef MYSQL_CLIENT
unknown's avatar
unknown committed
281 282
int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
		      uint fixed_dec, char filler, String *str);
unknown's avatar
unknown committed
283 284 285 286 287 288 289 290
#endif

inline
int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
		   longlong *l)
{
  my_decimal rounded;
  /* decimal_round can return only E_DEC_TRUNCATED */
291
  decimal_round((decimal_t*)d, &rounded, 0, HALF_UP);
unknown's avatar
unknown committed
292 293 294 295 296 297 298 299 300
  return check_result(mask, (unsigned_flag ?
			     decimal2ulonglong(&rounded, (ulonglong *)l) :
			     decimal2longlong(&rounded, l)));
}


inline
int my_decimal2double(uint mask, const my_decimal *d, double *result)
{
301
  /* No need to call check_result as this will always succeed */
302
  return decimal2double((decimal_t*) d, result);
unknown's avatar
unknown committed
303 304 305 306
}


inline
307
int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
unknown's avatar
unknown committed
308
{
309 310
  return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end),
                                   d);
unknown's avatar
unknown committed
311 312 313 314 315 316
}


int str2my_decimal(uint mask, const char *from, uint length,
                   CHARSET_INFO *charset, my_decimal *decimal_value);

317
#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
unknown's avatar
unknown committed
318 319 320 321 322
inline
int string2my_decimal(uint mask, const String *str, my_decimal *d)
{
  return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d);
}
323 324


325
my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec);
326 327 328


#endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */
unknown's avatar
unknown committed
329 330 331 332

inline
int double2my_decimal(uint mask, double val, my_decimal *d)
{
333
  return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d);
unknown's avatar
unknown committed
334 335 336 337 338 339 340 341 342 343 344 345 346
}


inline
int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
{
  return check_result(mask, (unsigned_flag ?
			     ulonglong2decimal((ulonglong)i, d) :
			     longlong2decimal(i, d)));
}


inline
347
void my_decimal_neg(decimal_t *arg)
unknown's avatar
unknown committed
348
{
unknown's avatar
unknown committed
349 350 351 352 353
  if (decimal_is_zero(arg))
  {
    arg->sign= 0;
    return;
  }
unknown's avatar
unknown committed
354 355 356 357 358 359 360 361
  decimal_neg(arg);
}


inline
int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
		   const my_decimal *b)
{
362 363 364
  return check_result_and_overflow(mask,
                                   decimal_add((decimal_t*)a,(decimal_t*)b,res),
                                   res);
unknown's avatar
unknown committed
365 366 367 368 369 370 371
}


inline
int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
		   const my_decimal *b)
{
372 373 374
  return check_result_and_overflow(mask,
                                   decimal_sub((decimal_t*)a,(decimal_t*)b,res),
                                   res);
unknown's avatar
unknown committed
375 376 377 378 379 380 381
}


inline
int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
		   const my_decimal *b)
{
382 383 384
  return check_result_and_overflow(mask,
                                   decimal_mul((decimal_t*)a,(decimal_t*)b,res),
                                   res);
unknown's avatar
unknown committed
385 386 387 388 389 390 391
}


inline
int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
		   const my_decimal *b, int div_scale_inc)
{
392 393 394 395
  return check_result_and_overflow(mask,
                                   decimal_div((decimal_t*)a,(decimal_t*)b,res,
                                               div_scale_inc),
                                   res);
unknown's avatar
unknown committed
396 397 398 399 400 401 402
}


inline
int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
		   const my_decimal *b)
{
403 404 405
  return check_result_and_overflow(mask,
                                   decimal_mod((decimal_t*)a,(decimal_t*)b,res),
                                   res);
unknown's avatar
unknown committed
406 407 408 409 410 411 412
}


/* Returns -1 if a<b, 1 if a>b and 0 if a==b */
inline
int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
{
413
  return decimal_cmp((decimal_t*) a, (decimal_t*) b);
unknown's avatar
unknown committed
414 415
}

416 417 418 419 420 421 422 423

inline
int my_decimal_intg(const my_decimal *a)
{
    return decimal_intg((decimal_t*) a);
}


unknown's avatar
unknown committed
424
inline
425 426 427 428 429 430 431 432 433 434 435
void my_decimal_trim(ulong *precision, uint *scale)
{
  if (!(*precision) && !(*scale))
  {
    *precision= 10;
    *scale= 0;
    return;
  }
}


unknown's avatar
unknown committed
436 437
#endif /*my_decimal_h*/