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