1 /* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /**
24   @file
25 
26   It is interface module to fixed precision decimals library.
27 
28   Most functions use 'uint mask' as parameter, if during operation error
29   which fit in this mask is detected then it will be processed automatically
30   here. (errors are E_DEC_* constants, see include/decimal.h)
31 
32   Most function are just inline wrappers around library calls
33 */
34 
35 #ifndef my_decimal_h
36 #define my_decimal_h
37 
38 #if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
39 #include "sql_string.h"                         /* String */
40 #endif
41 
42 C_MODE_START
43 #include <decimal.h>
44 C_MODE_END
45 
46 class String;
47 typedef struct st_mysql_time MYSQL_TIME;
48 
49 #define DECIMAL_LONGLONG_DIGITS 22
50 #define DECIMAL_LONG_DIGITS 10
51 #define DECIMAL_LONG3_DIGITS 8
52 
53 /** maximum length of buffer in our big digits (uint32). */
54 #define DECIMAL_BUFF_LENGTH 9
55 
56 /* the number of digits that my_decimal can possibly contain */
57 #define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
58 
59 
60 /**
61   maximum guaranteed precision of number in decimal digits (number of our
62   digits * number of decimal digits in one our big digit - number of decimal
63   digits in one our big digit decreased by 1 (because we always put decimal
64   point on the border of our big digits))
65 */
66 #define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
67 #define DECIMAL_MAX_SCALE 30
68 #define DECIMAL_NOT_SPECIFIED 31
69 
70 /**
71   maximum length of string representation (number of maximum decimal
72   digits + 1 position for sign + 1 position for decimal point, no terminator)
73 */
74 #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
75 
76 /**
77   maximum size of packet length.
78 */
79 #define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION
80 
81 
my_decimal_size(uint precision,uint scale)82 inline uint my_decimal_size(uint precision, uint scale)
83 {
84   /*
85     Always allocate more space to allow library to put decimal point
86     where it want
87   */
88   return decimal_size(precision, scale) + 1;
89 }
90 
91 
my_decimal_int_part(uint precision,uint decimals)92 inline int my_decimal_int_part(uint precision, uint decimals)
93 {
94   return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
95 }
96 
97 
98 /**
99   my_decimal class limits 'decimal_t' type to what we need in MySQL.
100 
101   It contains internally all necessary space needed by the instance so
102   no extra memory is needed. One should call fix_buffer_pointer() function
103   when he moves my_decimal objects in memory.
104 */
105 
106 class my_decimal :public decimal_t
107 {
108   /*
109     Several of the routines in strings/decimal.c have had buffer
110     overrun/underrun problems. These are *not* caught by valgrind.
111     To catch them, we allocate dummy fields around the buffer,
112     and test that their values do not change.
113    */
114 #if !defined(DBUG_OFF)
115   int foo1;
116 #endif
117 
118   decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
119 
120 #if !defined(DBUG_OFF)
121   int foo2;
122   static const int test_value= 123;
123 #endif
124 
125 public:
126 
my_decimal(const my_decimal & rhs)127   my_decimal(const my_decimal &rhs) : decimal_t(rhs)
128   {
129 #if !defined(DBUG_OFF)
130     foo1= test_value;
131     foo2= test_value;
132 #endif
133     for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
134       buffer[i]= rhs.buffer[i];
135     fix_buffer_pointer();
136   }
137 
138   my_decimal& operator=(const my_decimal &rhs)
139   {
140 #if !defined(DBUG_OFF)
141     foo1= test_value;
142     foo2= test_value;
143 #endif
144     if (this == &rhs)
145       return *this;
146     decimal_t::operator=(rhs);
147     for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
148       buffer[i]= rhs.buffer[i];
149     fix_buffer_pointer();
150     return *this;
151   }
152 
init()153   void init()
154   {
155 #if !defined(DBUG_OFF)
156     foo1= test_value;
157     foo2= test_value;
158 #endif
159     len= DECIMAL_BUFF_LENGTH;
160     buf= buffer;
161   }
162 
my_decimal()163   my_decimal()
164   {
165     init();
166   }
~my_decimal()167   ~my_decimal()
168   {
169     sanity_check();
170   }
171 
sanity_check()172   void sanity_check()
173   {
174     DBUG_ASSERT(foo1 == test_value);
175     DBUG_ASSERT(foo2 == test_value);
176   }
177 
fix_buffer_pointer()178   void fix_buffer_pointer() { buf= buffer; }
179 
sign()180   bool sign() const { return decimal_t::sign; }
sign(bool s)181   void sign(bool s) { decimal_t::sign= s; }
precision()182   uint precision() const { return intg + frac; }
183 
184   /** Swap two my_decimal values */
swap(my_decimal & rhs)185   void swap(my_decimal &rhs)
186   {
187     swap_variables(my_decimal, *this, rhs);
188   }
189 };
190 
191 
192 #ifndef DBUG_OFF
193 void print_decimal(const my_decimal *dec);
194 void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length);
195 const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
196 #else
197 #define dbug_decimal_as_string(A) NULL
198 #endif
199 
200 bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec,
201                      uint fixed_dec, char filler, String *str,
202                      const CHARSET_INFO *cs);
203 
204 extern my_decimal decimal_zero;
205 
206 #ifndef MYSQL_CLIENT
207 int decimal_operation_results(int result);
208 #else
decimal_operation_results(int result)209 inline int decimal_operation_results(int result)
210 {
211   return result;
212 }
213 #endif /*MYSQL_CLIENT*/
214 
215 inline
max_my_decimal(my_decimal * to,int precision,int frac)216 void max_my_decimal(my_decimal *to, int precision, int frac)
217 {
218   DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&&
219               (frac <= DECIMAL_MAX_SCALE));
220   max_decimal(precision, frac, to);
221 }
222 
max_internal_decimal(my_decimal * to)223 inline void max_internal_decimal(my_decimal *to)
224 {
225   max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
226 }
227 
check_result(uint mask,int result)228 inline int check_result(uint mask, int result)
229 {
230   if (result & mask)
231     decimal_operation_results(result);
232   return result;
233 }
234 
check_result_and_overflow(uint mask,int result,my_decimal * val)235 inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
236 {
237   if (check_result(mask, result) & E_DEC_OVERFLOW)
238   {
239     bool sign= val->sign();
240     val->fix_buffer_pointer();
241     max_internal_decimal(val);
242     val->sign(sign);
243   }
244   return result;
245 }
246 
my_decimal_length_to_precision(uint length,uint scale,bool unsigned_flag)247 inline uint my_decimal_length_to_precision(uint length, uint scale,
248                                            bool unsigned_flag)
249 {
250   /* Precision can't be negative thus ignore unsigned_flag when length is 0. */
251   DBUG_ASSERT(length || !scale);
252   return (uint) (length - (scale>0 ? 1:0) -
253                  (unsigned_flag || !length ? 0:1));
254 }
255 
my_decimal_precision_to_length_no_truncation(uint precision,uint8 scale,bool unsigned_flag)256 inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
257                                                            uint8 scale,
258                                                            bool unsigned_flag)
259 {
260   /*
261     When precision is 0 it means that original length was also 0. Thus
262     unsigned_flag is ignored in this case.
263   */
264   DBUG_ASSERT(precision || !scale);
265   return (uint32)(precision + (scale > 0 ? 1 : 0) +
266                   (unsigned_flag || !precision ? 0 : 1));
267 }
268 
my_decimal_precision_to_length(uint precision,uint8 scale,bool unsigned_flag)269 inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
270                                              bool unsigned_flag)
271 {
272   /*
273     When precision is 0 it means that original length was also 0. Thus
274     unsigned_flag is ignored in this case.
275   */
276   DBUG_ASSERT(precision || !scale);
277   set_if_smaller(precision, DECIMAL_MAX_PRECISION);
278   return my_decimal_precision_to_length_no_truncation(precision, scale,
279                                                       unsigned_flag);
280 }
281 
282 inline
my_decimal_string_length(const my_decimal * d)283 int my_decimal_string_length(const my_decimal *d)
284 {
285   /* length of string representation including terminating '\0' */
286   return decimal_string_size(d);
287 }
288 
289 
290 inline
my_decimal_max_length(const my_decimal * d)291 int my_decimal_max_length(const my_decimal *d)
292 {
293   /* -1 because we do not count \0 */
294   return decimal_string_size(d) - 1;
295 }
296 
297 
298 inline
my_decimal_get_binary_size(uint precision,uint scale)299 int my_decimal_get_binary_size(uint precision, uint scale)
300 {
301   return decimal_bin_size((int)precision, (int)scale);
302 }
303 
304 
305 inline
my_decimal2decimal(const my_decimal * from,my_decimal * to)306 void my_decimal2decimal(const my_decimal *from, my_decimal *to)
307 {
308   *to= *from;
309 }
310 
311 
312 int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
313 		      int scale);
314 
315 
316 inline
binary2my_decimal(uint mask,const uchar * bin,my_decimal * d,int prec,int scale)317 int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
318 		      int scale)
319 {
320   return check_result(mask, bin2decimal(bin, d, prec, scale));
321 }
322 
323 
324 inline
my_decimal_set_zero(my_decimal * d)325 int my_decimal_set_zero(my_decimal *d)
326 {
327   /*
328     We need the up-cast here, since my_decimal has sign() member functions,
329     which conflicts with decimal_t::size
330     (and decimal_make_zero is a macro, rather than a funcion).
331   */
332   decimal_make_zero(static_cast<decimal_t*>(d));
333   return 0;
334 }
335 
336 
337 inline
my_decimal_is_zero(const my_decimal * decimal_value)338 bool my_decimal_is_zero(const my_decimal *decimal_value)
339 {
340   return decimal_is_zero(decimal_value);
341 }
342 
343 
344 inline
my_decimal_round(uint mask,const my_decimal * from,int scale,bool truncate,my_decimal * to)345 int my_decimal_round(uint mask, const my_decimal *from, int scale,
346                      bool truncate, my_decimal *to)
347 {
348   return check_result(mask, decimal_round(from, to, scale,
349 					  (truncate ? TRUNCATE : HALF_UP)));
350 }
351 
352 
353 inline
my_decimal_floor(uint mask,const my_decimal * from,my_decimal * to)354 int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
355 {
356   return check_result(mask, decimal_round(from, to, 0, FLOOR));
357 }
358 
359 
360 inline
my_decimal_ceiling(uint mask,const my_decimal * from,my_decimal * to)361 int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
362 {
363   return check_result(mask, decimal_round(from, to, 0, CEILING));
364 }
365 
366 
str_set_decimal(const my_decimal * val,String * str,const CHARSET_INFO * cs)367 inline bool str_set_decimal(const my_decimal *val, String *str,
368                             const CHARSET_INFO *cs)
369 {
370   return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs);
371 }
372 
373 #ifndef MYSQL_CLIENT
374 class String;
375 int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
376 		      uint fixed_dec, char filler, String *str);
377 #endif
378 
379 inline
my_decimal2int(uint mask,const my_decimal * d,my_bool unsigned_flag,longlong * l)380 int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
381 		   longlong *l)
382 {
383   my_decimal rounded;
384   /* decimal_round can return only E_DEC_TRUNCATED */
385   decimal_round(d, &rounded, 0, HALF_UP);
386   return check_result(mask, (unsigned_flag ?
387 			     decimal2ulonglong(&rounded, (ulonglong *)l) :
388 			     decimal2longlong(&rounded, l)));
389 }
390 
391 
392 inline
my_decimal2double(uint,const my_decimal * d,double * result)393 int my_decimal2double(uint, const my_decimal *d, double *result)
394 {
395   /* No need to call check_result as this will always succeed */
396   return decimal2double(d, result);
397 }
398 
399 
my_decimal2lldiv_t(uint mask,const my_decimal * d,lldiv_t * to)400 inline int my_decimal2lldiv_t(uint mask, const my_decimal *d, lldiv_t *to)
401 {
402   return check_result(mask, decimal2lldiv_t(d, to));
403 }
404 
405 
str2my_decimal(uint mask,const char * str,my_decimal * d,char ** end)406 inline int str2my_decimal(uint mask, const char *str,
407                           my_decimal *d, char **end)
408 {
409   return check_result_and_overflow(mask, string2decimal(str, d, end), d);
410 }
411 
412 
413 int str2my_decimal(uint mask, const char *from, uint length,
414                    const CHARSET_INFO *charset, my_decimal *decimal_value);
415 
416 #if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
417 inline
string2my_decimal(uint mask,const String * str,my_decimal * d)418 int string2my_decimal(uint mask, const String *str, my_decimal *d)
419 {
420   return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d);
421 }
422 
423 
424 my_decimal *date2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec);
425 my_decimal *time2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec);
426 my_decimal *timeval2my_decimal(const struct timeval *tm, my_decimal *dec);
427 
428 #endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */
429 
430 inline
double2my_decimal(uint mask,double val,my_decimal * d)431 int double2my_decimal(uint mask, double val, my_decimal *d)
432 {
433   return check_result_and_overflow(mask, double2decimal(val, d), d);
434 }
435 
436 
437 inline
int2my_decimal(uint mask,longlong i,my_bool unsigned_flag,my_decimal * d)438 int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
439 {
440   return check_result(mask, (unsigned_flag ?
441 			     ulonglong2decimal((ulonglong)i, d) :
442 			     longlong2decimal(i, d)));
443 }
444 
445 
446 inline
my_decimal_neg(decimal_t * arg)447 void my_decimal_neg(decimal_t *arg)
448 {
449   if (decimal_is_zero(arg))
450   {
451     arg->sign= 0;
452     return;
453   }
454   decimal_neg(arg);
455 }
456 
457 
458 inline
my_decimal_add(uint mask,my_decimal * res,const my_decimal * a,const my_decimal * b)459 int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
460 		   const my_decimal *b)
461 {
462   return check_result_and_overflow(mask,
463                                    decimal_add(a, b, res),
464                                    res);
465 }
466 
467 
468 inline
my_decimal_sub(uint mask,my_decimal * res,const my_decimal * a,const my_decimal * b)469 int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
470 		   const my_decimal *b)
471 {
472   return check_result_and_overflow(mask,
473                                    decimal_sub(a, b, res),
474                                    res);
475 }
476 
477 
478 inline
my_decimal_mul(uint mask,my_decimal * res,const my_decimal * a,const my_decimal * b)479 int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
480 		   const my_decimal *b)
481 {
482   return check_result_and_overflow(mask,
483                                    decimal_mul(a, b, res),
484                                    res);
485 }
486 
487 
488 inline
my_decimal_div(uint mask,my_decimal * res,const my_decimal * a,const my_decimal * b,int div_scale_inc)489 int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
490 		   const my_decimal *b, int div_scale_inc)
491 {
492   return check_result_and_overflow(mask,
493                                    decimal_div(a, b, res, div_scale_inc),
494                                    res);
495 }
496 
497 
498 inline
my_decimal_mod(uint mask,my_decimal * res,const my_decimal * a,const my_decimal * b)499 int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
500 		   const my_decimal *b)
501 {
502   return check_result_and_overflow(mask,
503                                    decimal_mod(a, b, res),
504                                    res);
505 }
506 
507 
508 /**
509   @return
510     -1 if a<b, 1 if a>b and 0 if a==b
511 */
512 inline
my_decimal_cmp(const my_decimal * a,const my_decimal * b)513 int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
514 {
515   return decimal_cmp(a, b);
516 }
517 
518 
519 inline
my_decimal_intg(const my_decimal * a)520 int my_decimal_intg(const my_decimal *a)
521 {
522   return decimal_intg(a);
523 }
524 
525 
526 void my_decimal_trim(ulong *precision, uint *scale);
527 
528 
529 #endif /*my_decimal_h*/
530 
531