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-1301, 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
36C_MODE_START
37#include <decimal.h>
38#include <my_decimal_limits.h>
39C_MODE_END
40
41class String;
42typedef 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
50inline 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
60inline 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
74class 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
93public:
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
154void print_decimal(const my_decimal *dec);
155void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length);
156const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
157#else
158#define dbug_decimal_as_string(A) NULL
159#endif
160
161bool 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
165extern my_decimal decimal_zero;
166
167#ifndef MYSQL_CLIENT
168int decimal_operation_results(int result, const char *value, const char *type);
169#else
170inline int decimal_operation_results(int result, const char *value,
171 const char *type)
172{
173 return result;
174}
175#endif /*MYSQL_CLIENT*/
176
177inline
178void 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
185inline void max_internal_decimal(my_decimal *to)
186{
187 max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
188}
189
190inline int check_result(uint mask, int result)
191{
192 if (result & mask)
193 decimal_operation_results(result, "", "DECIMAL");
194 return result;
195}
196
197inline 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
209inline 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
218inline 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
231inline 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
244inline
245int 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
252inline
253int 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
260inline
261int my_decimal_get_binary_size(uint precision, uint scale)
262{
263 return decimal_bin_size((int)precision, (int)scale);
264}
265
266
267inline
268void my_decimal2decimal(const my_decimal *from, my_decimal *to)
269{
270 *to= *from;
271}
272
273
274int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
275 int scale);
276
277
278inline
279int 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
286inline
287int 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
299inline
300bool my_decimal_is_zero(const my_decimal *decimal_value)
301{
302 return decimal_is_zero(decimal_value);
303}
304
305
306inline
307int my_decimal_round(uint mask, const my_decimal *from, int scale,
308 bool truncate, my_decimal *to)
309{
310 return check_result(mask, decimal_round(from, to, scale,
311 (truncate ? TRUNCATE : HALF_UP)));
312}
313
314
315inline
316int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
317{
318 return check_result(mask, decimal_round(from, to, 0, FLOOR));
319}
320
321
322inline
323int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
324{
325 return check_result(mask, decimal_round(from, to, 0, CEILING));
326}
327
328
329inline bool str_set_decimal(const my_decimal *val, String *str,
330 CHARSET_INFO *cs)
331{
332 return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs);
333}
334
335#ifndef MYSQL_CLIENT
336class String;
337int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
338 uint fixed_dec, char filler, String *str);
339#endif
340
341bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec);
342
343my_decimal *seconds2my_decimal(bool sign, ulonglong sec, ulong microsec,
344 my_decimal *d);
345
346#define TIME_to_my_decimal(TIME, DECIMAL) \
347 seconds2my_decimal((TIME)->neg, TIME_to_ulonglong(TIME), \
348 (TIME)->second_part, (DECIMAL))
349
350int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag,
351 longlong *l);
352
353inline
354int my_decimal2double(uint, const decimal_t *d, double *result)
355{
356 /* No need to call check_result as this will always succeed */
357 return decimal2double(d, result);
358}
359
360
361inline
362int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
363{
364 return check_result_and_overflow(mask, string2decimal(str, d, end), d);
365}
366
367
368int str2my_decimal(uint mask, const char *from, size_t length,
369 CHARSET_INFO *charset, my_decimal *decimal_value,
370 const char **end);
371
372inline int str2my_decimal(uint mask, const char *from, size_t length,
373 CHARSET_INFO *charset, my_decimal *decimal_value)
374{
375 const char *end;
376 return str2my_decimal(mask, from, length, charset, decimal_value, &end);
377}
378
379#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
380inline
381int string2my_decimal(uint mask, const String *str, my_decimal *d)
382{
383 const char *end;
384 return str2my_decimal(mask, str->ptr(), str->length(), str->charset(),
385 d, &end);
386}
387
388
389my_decimal *date2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec);
390
391
392#endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */
393
394inline
395int double2my_decimal(uint mask, double val, my_decimal *d)
396{
397 return check_result_and_overflow(mask, double2decimal(val, d), d);
398}
399
400
401inline
402int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
403{
404 return check_result(mask, (unsigned_flag ?
405 ulonglong2decimal((ulonglong)i, d) :
406 longlong2decimal(i, d)));
407}
408
409inline
410void decimal2my_decimal(decimal_t *from, my_decimal *to)
411{
412 DBUG_ASSERT(to->len >= from->len);
413 to->intg= from->intg;
414 to->frac= from->frac;
415 to->sign(from->sign);
416 memcpy(to->buf, from->buf, to->len*sizeof(decimal_digit_t));
417}
418
419
420inline
421void my_decimal_neg(decimal_t *arg)
422{
423 if (decimal_is_zero(arg))
424 {
425 arg->sign= 0;
426 return;
427 }
428 decimal_neg(arg);
429}
430
431
432inline
433int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
434 const my_decimal *b)
435{
436 return check_result_and_overflow(mask,
437 decimal_add(a, b, res),
438 res);
439}
440
441
442inline
443int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
444 const my_decimal *b)
445{
446 return check_result_and_overflow(mask,
447 decimal_sub(a, b, res),
448 res);
449}
450
451
452inline
453int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
454 const my_decimal *b)
455{
456 return check_result_and_overflow(mask,
457 decimal_mul(a, b, res),
458 res);
459}
460
461
462inline
463int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
464 const my_decimal *b, int div_scale_inc)
465{
466 return check_result_and_overflow(mask,
467 decimal_div(a, b, res, div_scale_inc),
468 res);
469}
470
471
472inline
473int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
474 const my_decimal *b)
475{
476 return check_result_and_overflow(mask,
477 decimal_mod(a, b, res),
478 res);
479}
480
481/**
482 @return
483 -1 if a<b, 1 if a>b and 0 if a==b
484*/
485inline
486int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
487{
488 return decimal_cmp(a, b);
489}
490
491
492inline
493int my_decimal_intg(const my_decimal *a)
494{
495 return decimal_intg(a);
496}
497
498
499void my_decimal_trim(ulonglong *precision, uint *scale);
500
501
502#endif /*my_decimal_h*/
503
504