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