~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/my_decimal.cc

  • Committer: Brian Aker
  • Date: 2010-03-31 22:35:54 UTC
  • mfrom: (1410.3.3 ded_my_clean)
  • Revision ID: brian@gaz-20100331223554-yswmkmhxbqe724oe
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2005-2006 MySQL AB
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 as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
#include "config.h"
17
 
#include <time.h>
18
 
#include "drizzled/current_session.h"
19
 
#include "drizzled/error.h"
20
 
#include "drizzled/field.h"
21
 
#include "drizzled/internal/my_sys.h"
22
 
 
23
 
namespace drizzled
24
 
{
25
 
 
26
 
/**
27
 
  report result of decimal operation.
28
 
 
29
 
  @param result  decimal library return code (E_DEC_* see include/decimal.h)
30
 
 
31
 
  @todo
32
 
    Fix error messages
33
 
 
34
 
  @return
35
 
    result
36
 
*/
37
 
 
38
 
int decimal_operation_results(int result)
39
 
{
40
 
  switch (result) {
41
 
  case E_DEC_OK:
42
 
    break;
43
 
  case E_DEC_TRUNCATED:
44
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
45
 
                        ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
46
 
                        "", (long)-1);
47
 
    break;
48
 
  case E_DEC_OVERFLOW:
49
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
50
 
                        ER_TRUNCATED_WRONG_VALUE,
51
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
52
 
                        "DECIMAL", "");
53
 
    break;
54
 
  case E_DEC_DIV_ZERO:
55
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
56
 
                        ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
57
 
    break;
58
 
  case E_DEC_BAD_NUM:
59
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
60
 
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
61
 
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
62
 
                        "decimal", "", "", (long)-1);
63
 
    break;
64
 
  case E_DEC_OOM:
65
 
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
66
 
    break;
67
 
  default:
68
 
    assert(0);
69
 
  }
70
 
  return result;
71
 
}
72
 
 
73
 
 
74
 
/**
75
 
  @brief Converting decimal to string
76
 
 
77
 
  @details Convert given my_decimal to String; allocate buffer as needed.
78
 
 
79
 
  @param[in]   mask        what problems to warn on (mask of E_DEC_* values)
80
 
  @param[in]   d           the decimal to print
81
 
  @param[in]   fixed_prec  overall number of digits if ZEROFILL, 0 otherwise
82
 
  @param[in]   fixed_dec   number of decimal places (if fixed_prec != 0)
83
 
  @param[in]   filler      what char to pad with (ZEROFILL et al.)
84
 
  @param[out]  *str        where to store the resulting string
85
 
 
86
 
  @return error coce
87
 
    @retval E_DEC_OK
88
 
    @retval E_DEC_TRUNCATED
89
 
    @retval E_DEC_OVERFLOW
90
 
    @retval E_DEC_OOM
91
 
*/
92
 
 
93
 
int my_decimal2string(uint32_t mask, const my_decimal *d,
94
 
                      uint32_t fixed_prec, uint32_t fixed_dec,
95
 
                      char filler, String *str)
96
 
{
97
 
  /*
98
 
    Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
99
 
    holds true iff the type is also ZEROFILL, which in turn implies
100
 
    UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
101
 
    the user requested, plus one for a possible decimal point, plus
102
 
    one if the user only wanted decimal places, but we force a leading
103
 
    zero on them. Because the type is implicitly UNSIGNED, we do not
104
 
    need to reserve a character for the sign. For all other cases,
105
 
    fixed_prec will be 0, and my_decimal_string_length() will be called
106
 
    instead to calculate the required size of the buffer.
107
 
  */
108
 
  int length= (fixed_prec
109
 
               ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
110
 
               : my_decimal_string_length(d));
111
 
  int result;
112
 
  if (str->alloc(length))
113
 
    return check_result(mask, E_DEC_OOM);
114
 
  result= decimal2string((decimal_t*) d, (char*) str->ptr(),
115
 
                         &length, (int)fixed_prec, fixed_dec,
116
 
                         filler);
117
 
  str->length(length);
118
 
  return check_result(mask, result);
119
 
}
120
 
 
121
 
 
122
 
/*
123
 
  Convert from decimal to binary representation
124
 
 
125
 
  SYNOPSIS
126
 
    my_decimal2binary()
127
 
    mask        error processing mask
128
 
    d           number for conversion
129
 
    bin         pointer to buffer where to write result
130
 
    prec        overall number of decimal digits
131
 
    scale       number of decimal digits after decimal point
132
 
 
133
 
  NOTE
134
 
    Before conversion we round number if it need but produce truncation
135
 
    error in this case
136
 
 
137
 
  RETURN
138
 
    E_DEC_OK
139
 
    E_DEC_TRUNCATED
140
 
    E_DEC_OVERFLOW
141
 
*/
142
 
 
143
 
int my_decimal2binary(uint32_t mask, const my_decimal *d, unsigned char *bin, int prec,
144
 
                      int scale)
145
 
{
146
 
  int err1= E_DEC_OK, err2;
147
 
  my_decimal rounded;
148
 
  my_decimal2decimal(d, &rounded);
149
 
  rounded.frac= decimal_actual_fraction(&rounded);
150
 
  if (scale < rounded.frac)
151
 
  {
152
 
    err1= E_DEC_TRUNCATED;
153
 
    /* decimal_round can return only E_DEC_TRUNCATED */
154
 
    decimal_round(&rounded, &rounded, scale, HALF_UP);
155
 
  }
156
 
  err2= decimal2bin(&rounded, bin, prec, scale);
157
 
  if (!err2)
158
 
    err2= err1;
159
 
  return check_result(mask, err2);
160
 
}
161
 
 
162
 
 
163
 
/*
164
 
  Convert string for decimal when string can be in some multibyte charset
165
 
 
166
 
  SYNOPSIS
167
 
    str2my_decimal()
168
 
    mask            error processing mask
169
 
    from            string to process
170
 
    length          length of given string
171
 
    charset         charset of given string
172
 
    decimal_value   buffer for result storing
173
 
 
174
 
  RESULT
175
 
    E_DEC_OK
176
 
    E_DEC_TRUNCATED
177
 
    E_DEC_OVERFLOW
178
 
    E_DEC_BAD_NUM
179
 
    E_DEC_OOM
180
 
*/
181
 
 
182
 
int str2my_decimal(uint32_t mask, const char *from, uint32_t length,
183
 
                   const CHARSET_INFO * charset, my_decimal *decimal_value)
184
 
{
185
 
  char *end, *from_end;
186
 
  int err;
187
 
  char buff[STRING_BUFFER_USUAL_SIZE];
188
 
  String tmp(buff, sizeof(buff), &my_charset_bin);
189
 
  if (charset->mbminlen > 1)
190
 
  {
191
 
    uint32_t dummy_errors;
192
 
    tmp.copy(from, length, charset, &my_charset_utf8_general_ci, &dummy_errors);
193
 
    from= tmp.ptr();
194
 
    length=  tmp.length();
195
 
    charset= &my_charset_bin;
196
 
  }
197
 
  from_end= end= (char*) from+length;
198
 
  err= string2decimal((char *)from, (decimal_t*) decimal_value, &end);
199
 
  if (end != from_end && !err)
200
 
  {
201
 
    /* Give warning if there is something other than end space */
202
 
    for ( ; end < from_end; end++)
203
 
    {
204
 
      if (!my_isspace(&my_charset_utf8_general_ci, *end))
205
 
      {
206
 
        err= E_DEC_TRUNCATED;
207
 
        break;
208
 
      }
209
 
    }
210
 
  }
211
 
  check_result_and_overflow(mask, err, decimal_value);
212
 
  return err;
213
 
}
214
 
 
215
 
 
216
 
my_decimal *date2my_decimal(DRIZZLE_TIME *ltime, my_decimal *dec)
217
 
{
218
 
  int64_t date;
219
 
  date = (ltime->year*100L + ltime->month)*100L + ltime->day;
220
 
  if (ltime->time_type > DRIZZLE_TIMESTAMP_DATE)
221
 
    date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
222
 
  if (int2my_decimal(E_DEC_FATAL_ERROR, date, false, dec))
223
 
    return dec;
224
 
  if (ltime->second_part)
225
 
  {
226
 
    dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
227
 
    dec->frac= 6;
228
 
  }
229
 
  return dec;
230
 
}
231
 
 
232
 
 
233
 
void my_decimal_trim(uint32_t *precision, uint32_t *scale)
234
 
{
235
 
  if (!(*precision) && !(*scale))
236
 
  {
237
 
    *precision= 10;
238
 
    *scale= 0;
239
 
    return;
240
 
  }
241
 
}
242
 
 
243
 
} /* namespace drizzled */