The world's most popular open source database
00001 /* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* 00018 It is interface module to fixed precision decimals library. 00019 00020 Most functions use 'uint mask' as parameter, if during operation error 00021 which fit in this mask is detected then it will be processed automatically 00022 here. (errors are E_DEC_* constants, see include/decimal.h) 00023 00024 Most function are just inline wrappers around library calls 00025 */ 00026 00027 #ifndef my_decimal_h 00028 #define my_decimal_h 00029 00030 C_MODE_START 00031 #include <decimal.h> 00032 C_MODE_END 00033 00034 #define DECIMAL_LONGLONG_DIGITS 22 00035 #define DECIMAL_LONG_DIGITS 10 00036 #define DECIMAL_LONG3_DIGITS 8 00037 00038 /* maximum length of buffer in our big digits (uint32) */ 00039 #define DECIMAL_BUFF_LENGTH 9 00040 /* 00041 maximum guaranteed precision of number in decimal digits (number of our 00042 digits * number of decimal digits in one our big digit - number of decimal 00043 digits in one our big digit decreased on 1 (because we always put decimal 00044 point on the border of our big digits)) 00045 */ 00046 #define DECIMAL_MAX_PRECISION ((DECIMAL_BUFF_LENGTH * 9) - 8*2) 00047 #define DECIMAL_MAX_SCALE 30 00048 #define DECIMAL_NOT_SPECIFIED 31 00049 00050 /* 00051 maximum length of string representation (number of maximum decimal 00052 digits + 1 position for sign + 1 position for decimal point) 00053 */ 00054 #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_PRECISION + 2) 00055 /* 00056 maximum size of packet length 00057 */ 00058 #define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION 00059 00060 00061 inline uint my_decimal_size(uint precision, uint scale) 00062 { 00063 /* 00064 Always allocate more space to allow library to put decimal point 00065 where it want 00066 */ 00067 return decimal_size(precision, scale) + 1; 00068 } 00069 00070 00071 inline int my_decimal_int_part(uint precision, uint decimals) 00072 { 00073 return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals); 00074 } 00075 00076 00077 /* 00078 my_decimal class limits 'decimal_t' type to what we need in MySQL 00079 It contains internally all necessary space needed by the instance so 00080 no extra memory is needed. One should call fix_buffer_pointer() function 00081 when he moves my_decimal objects in memory 00082 */ 00083 00084 class my_decimal :public decimal_t 00085 { 00086 decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; 00087 00088 public: 00089 00090 void init() 00091 { 00092 len= DECIMAL_BUFF_LENGTH; 00093 buf= buffer; 00094 #if !defined (HAVE_purify) && !defined(DBUG_OFF) 00095 /* Set buffer to 'random' value to find wrong buffer usage */ 00096 for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) 00097 buffer[i]= i; 00098 #endif 00099 } 00100 my_decimal() 00101 { 00102 init(); 00103 } 00104 void fix_buffer_pointer() { buf= buffer; } 00105 00106 bool sign() const { return decimal_t::sign; } 00107 void sign(bool s) { decimal_t::sign= s; } 00108 uint precision() const { return intg + frac; } 00109 }; 00110 00111 00112 #ifndef DBUG_OFF 00113 void print_decimal(const my_decimal *dec); 00114 void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); 00115 const char *dbug_decimal_as_string(char *buff, const my_decimal *val); 00116 #else 00117 #define dbug_decimal_as_string(A) NULL 00118 #endif 00119 00120 #ifndef MYSQL_CLIENT 00121 int decimal_operation_results(int result); 00122 #else 00123 inline int decimal_operation_results(int result) 00124 { 00125 return result; 00126 } 00127 #endif /*MYSQL_CLIENT*/ 00128 00129 inline 00130 void max_my_decimal(my_decimal *to, int precision, int frac) 00131 { 00132 DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& 00133 (frac <= DECIMAL_MAX_SCALE)); 00134 max_decimal(precision, frac, (decimal_t*) to); 00135 } 00136 00137 inline void max_internal_decimal(my_decimal *to) 00138 { 00139 max_my_decimal(to, DECIMAL_MAX_PRECISION, 0); 00140 } 00141 00142 inline int check_result(uint mask, int result) 00143 { 00144 if (result & mask) 00145 decimal_operation_results(result); 00146 return result; 00147 } 00148 00149 inline int check_result_and_overflow(uint mask, int result, my_decimal *val) 00150 { 00151 if (check_result(mask, result) & E_DEC_OVERFLOW) 00152 { 00153 bool sign= val->sign(); 00154 val->fix_buffer_pointer(); 00155 max_internal_decimal(val); 00156 val->sign(sign); 00157 } 00158 return result; 00159 } 00160 00161 inline uint my_decimal_length_to_precision(uint length, uint scale, 00162 bool unsigned_flag) 00163 { 00164 return (uint) (length - (scale>0 ? 1:0) - (unsigned_flag ? 0:1)); 00165 } 00166 00167 inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, 00168 bool unsigned_flag) 00169 { 00170 set_if_smaller(precision, DECIMAL_MAX_PRECISION); 00171 return (uint32)(precision + (scale>0 ? 1:0) + (unsigned_flag ? 0:1)); 00172 } 00173 00174 inline 00175 int my_decimal_string_length(const my_decimal *d) 00176 { 00177 return decimal_string_size(d); 00178 } 00179 00180 00181 inline 00182 int my_decimal_max_length(const my_decimal *d) 00183 { 00184 /* -1 because we do not count \0 */ 00185 return decimal_string_size(d) - 1; 00186 } 00187 00188 00189 inline 00190 int my_decimal_get_binary_size(uint precision, uint scale) 00191 { 00192 return decimal_bin_size((int)precision, (int)scale); 00193 } 00194 00195 00196 inline 00197 void my_decimal2decimal(const my_decimal *from, my_decimal *to) 00198 { 00199 *to= *from; 00200 to->fix_buffer_pointer(); 00201 } 00202 00203 00204 int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec, 00205 int scale); 00206 00207 00208 inline 00209 int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec, 00210 int scale) 00211 { 00212 return check_result(mask, bin2decimal((char *)bin, (decimal_t*) d, prec, 00213 scale)); 00214 } 00215 00216 00217 inline 00218 int my_decimal_set_zero(my_decimal *d) 00219 { 00220 decimal_make_zero(((decimal_t*) d)); 00221 return 0; 00222 } 00223 00224 00225 inline 00226 bool my_decimal_is_zero(const my_decimal *decimal_value) 00227 { 00228 return decimal_is_zero((decimal_t*) decimal_value); 00229 } 00230 00231 00232 inline 00233 int my_decimal_round(uint mask, const my_decimal *from, int scale, 00234 bool truncate, my_decimal *to) 00235 { 00236 return check_result(mask, decimal_round((decimal_t*) from, to, scale, 00237 (truncate ? TRUNCATE : HALF_UP))); 00238 } 00239 00240 00241 inline 00242 int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) 00243 { 00244 return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR)); 00245 } 00246 00247 00248 inline 00249 int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) 00250 { 00251 return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING)); 00252 } 00253 00254 00255 #ifndef MYSQL_CLIENT 00256 int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, 00257 uint fixed_dec, char filler, String *str); 00258 #endif 00259 00260 inline 00261 int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, 00262 longlong *l) 00263 { 00264 my_decimal rounded; 00265 /* decimal_round can return only E_DEC_TRUNCATED */ 00266 decimal_round((decimal_t*)d, &rounded, 0, HALF_UP); 00267 return check_result(mask, (unsigned_flag ? 00268 decimal2ulonglong(&rounded, (ulonglong *)l) : 00269 decimal2longlong(&rounded, l))); 00270 } 00271 00272 00273 inline 00274 int my_decimal2double(uint mask, const my_decimal *d, double *result) 00275 { 00276 /* No need to call check_result as this will always succeed */ 00277 return decimal2double((decimal_t*) d, result); 00278 } 00279 00280 00281 inline 00282 int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) 00283 { 00284 return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end), 00285 d); 00286 } 00287 00288 00289 int str2my_decimal(uint mask, const char *from, uint length, 00290 CHARSET_INFO *charset, my_decimal *decimal_value); 00291 00292 #if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) 00293 inline 00294 int string2my_decimal(uint mask, const String *str, my_decimal *d) 00295 { 00296 return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d); 00297 } 00298 #endif 00299 00300 inline 00301 int double2my_decimal(uint mask, double val, my_decimal *d) 00302 { 00303 return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d); 00304 } 00305 00306 00307 inline 00308 int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) 00309 { 00310 return check_result(mask, (unsigned_flag ? 00311 ulonglong2decimal((ulonglong)i, d) : 00312 longlong2decimal(i, d))); 00313 } 00314 00315 00316 inline 00317 void my_decimal_neg(decimal_t *arg) 00318 { 00319 if (decimal_is_zero(arg)) 00320 { 00321 arg->sign= 0; 00322 return; 00323 } 00324 decimal_neg(arg); 00325 } 00326 00327 00328 inline 00329 int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, 00330 const my_decimal *b) 00331 { 00332 return check_result_and_overflow(mask, 00333 decimal_add((decimal_t*)a,(decimal_t*)b,res), 00334 res); 00335 } 00336 00337 00338 inline 00339 int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, 00340 const my_decimal *b) 00341 { 00342 return check_result_and_overflow(mask, 00343 decimal_sub((decimal_t*)a,(decimal_t*)b,res), 00344 res); 00345 } 00346 00347 00348 inline 00349 int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, 00350 const my_decimal *b) 00351 { 00352 return check_result_and_overflow(mask, 00353 decimal_mul((decimal_t*)a,(decimal_t*)b,res), 00354 res); 00355 } 00356 00357 00358 inline 00359 int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, 00360 const my_decimal *b, int div_scale_inc) 00361 { 00362 return check_result_and_overflow(mask, 00363 decimal_div((decimal_t*)a,(decimal_t*)b,res, 00364 div_scale_inc), 00365 res); 00366 } 00367 00368 00369 inline 00370 int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, 00371 const my_decimal *b) 00372 { 00373 return check_result_and_overflow(mask, 00374 decimal_mod((decimal_t*)a,(decimal_t*)b,res), 00375 res); 00376 } 00377 00378 00379 /* Returns -1 if a<b, 1 if a>b and 0 if a==b */ 00380 inline 00381 int my_decimal_cmp(const my_decimal *a, const my_decimal *b) 00382 { 00383 return decimal_cmp((decimal_t*) a, (decimal_t*) b); 00384 } 00385 00386 00387 inline 00388 int my_decimal_intg(const my_decimal *a) 00389 { 00390 return decimal_intg((decimal_t*) a); 00391 } 00392 00393 00394 #endif /*my_decimal_h*/ 00395
1.4.7

