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