diff options
author | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
---|---|---|
committer | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
commit | 91db48e35a57421c00f65d5ce82e84b843ceec22 (patch) | |
tree | 9631c72d46b0fd08479ad02de00e5846cd339cda /sql/my_decimal.cc | |
parent | 63bcbfc4339ae843dc367d08fff0760da4d484c3 (diff) | |
download | mariadb-git-91db48e35a57421c00f65d5ce82e84b843ceec22.tar.gz |
Precision Math implementation
BitKeeper/etc/ignore:
Added client/decimal.c client/my_decimal.cc client/my_decimal.h to the ignore list
Diffstat (limited to 'sql/my_decimal.cc')
-rw-r--r-- | sql/my_decimal.cc | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc new file mode 100644 index 00000000000..eafcd2eaaf3 --- /dev/null +++ b/sql/my_decimal.cc @@ -0,0 +1,212 @@ +/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "mysql_priv.h" + +#ifndef MYSQL_CLIENT +/* + report result of decimal operation + + SYNOPSIS + decimal_operation_results() + result decimal library return code (E_DEC_* see include/decimal.h) + + return + result +*/ +int decimal_operation_results(int result) +{ + switch (result) + { + case E_DEC_OK: + break; +//TODO: fix error messages + case E_DEC_TRUNCATED: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED), + "", (long)-1); + break; + case E_DEC_OVERFLOW: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_WARN_DATA_OUT_OF_RANGE, + ER(ER_WARN_DATA_OUT_OF_RANGE), + "", (long)-1); + break; + case E_DEC_DIV_ZERO: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO)); + break; + case E_DEC_BAD_NUM: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", "", "", (long)-1); + break; + case E_DEC_OOM: + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + break; + default: + DBUG_ASSERT(0); + } + return result; +} + + +/* + Converting decimal to string + + SYNOPSIS + my_decimal2string() + + return + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + E_DEC_OOM +*/ + +int my_decimal2string(uint mask, const my_decimal *d, + int fixed_prec, int fixed_dec, + char filler, String *str) +{ + int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d)); + int result; + if (str->alloc(length)) + return check_result(mask, E_DEC_OOM); + char *sptr= (char *)str->ptr(); + int res= decimal2string((decimal *)d, sptr, + &length, fixed_prec, fixed_dec, + filler); + result= check_result(mask, res); + str->length(length); + return result; +} + + +/* + Convert from decimal to binary representation + + SYNOPSIS + my_decimal2binary() + mask error processing mask + d number for conversion + bin pointer to buffer where to write result + prec overall number of decimal digits + scale number of decimal digits after decimal point + + NOTE + Before conversion we round number if it need but produce truncation + error in this case + + RETURN + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW +*/ + +int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, + int scale) +{ + int err1= E_DEC_OK, err2; + my_decimal rounded; + my_decimal2decimal(d, &rounded); + decimal_optimize_fraction(&rounded); + if (scale < rounded.frac) + { + err1= E_DEC_TRUNCATED; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round(&rounded, &rounded, scale, HALF_UP); + } + err2= decimal2bin(&rounded, bin, prec, scale); + if (!err2) + err2= err1; + return check_result(mask, err2); +} + + +/* + Convert string for decimal when string can be in some multibyte charset + + SYNOPSIS + str2my_decimal() + mask error processing mask + from string to process + length length of given string + charset charset of given string + decimal_value buffer for result storing + + RESULT + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + E_DEC_BAD_NUM + E_DEC_OOM +*/ +int str2my_decimal(uint mask, const char *from, uint length, + CHARSET_INFO *charset, my_decimal *decimal_value) +{ + char *end; + int err; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + if (charset->mbminlen > 1) + { + uint dummy_errors; + tmp.copy(from, length, charset, &my_charset_latin1, &dummy_errors); + from= tmp.ptr(); + length= tmp.length(); + charset= &my_charset_bin; + } + my_decimal_set_zero(decimal_value); + err= string2decimal((char *)from, (decimal *)decimal_value, &end); + if (*end && !err) + err= E_DEC_TRUNCATED; + check_result(mask, err); + return err; +} + + +#ifndef DBUG_OFF +/* routines for debugging print */ + +/* print decimal */ +void +print_decimal(const my_decimal *dec) +{ + fprintf(DBUG_FILE, + "\nDecimal: sign: %d intg: %d frac: %d \n\ +%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n", + dec->sign(), dec->intg, dec->frac, + dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3], + dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]); +} + + +/* print decimal with its binary representation */ +void +print_decimal_buff(const my_decimal *dec, const byte* ptr, int length) +{ + print_decimal(dec); + fprintf(DBUG_FILE, "Record: "); + for(int i= 0; i < length; i++) + { + fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]); + } + fprintf(DBUG_FILE, "\n"); +} +#endif + + +#endif /*MYSQL_CLIENT*/ |