~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/decimal.cc

  • Committer: Djellel E. Difallah
  • Date: 2010-03-27 10:10:49 UTC
  • mto: This revision was merged to the branch mainline in revision 1429.
  • Revision ID: ded@ubuntu-20100327101049-oo3arvatjoyku124
merge my_decimal and decimal

Show diffs side-by-side

added added

removed removed

Lines of Context:
112
112
#endif
113
113
 
114
114
#include <algorithm>
 
115
#include <time.h>
 
116
#include "drizzled/current_session.h"
 
117
#include "drizzled/error.h"
 
118
#include "drizzled/field.h"
 
119
#include "drizzled/internal/my_sys.h"
115
120
 
116
121
using namespace std;
117
122
 
118
123
namespace drizzled
119
124
{
 
125
/**
 
126
  report result of decimal operation.
 
127
 
 
128
  @param result  decimal library return code (E_DEC_* see include/decimal.h)
 
129
 
 
130
  @todo
 
131
    Fix error messages
 
132
 
 
133
  @return
 
134
    result
 
135
*/
 
136
 
 
137
int decimal_operation_results(int result)
 
138
{
 
139
  switch (result) {
 
140
  case E_DEC_OK:
 
141
    break;
 
142
  case E_DEC_TRUNCATED:
 
143
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
144
                        ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
 
145
                        "", (long)-1);
 
146
    break;
 
147
  case E_DEC_OVERFLOW:
 
148
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
149
                        ER_TRUNCATED_WRONG_VALUE,
 
150
                        ER(ER_TRUNCATED_WRONG_VALUE),
 
151
                        "DECIMAL", "");
 
152
    break;
 
153
  case E_DEC_DIV_ZERO:
 
154
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
155
                        ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
 
156
    break;
 
157
  case E_DEC_BAD_NUM:
 
158
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
159
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
 
160
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
 
161
                        "decimal", "", "", (long)-1);
 
162
    break;
 
163
  case E_DEC_OOM:
 
164
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
 
165
    break;
 
166
  default:
 
167
    assert(0);
 
168
  }
 
169
  return result;
 
170
}
 
171
 
 
172
 
 
173
/**
 
174
  @brief Converting decimal to string
 
175
 
 
176
  @details Convert given my_decimal to String; allocate buffer as needed.
 
177
 
 
178
  @param[in]   mask        what problems to warn on (mask of E_DEC_* values)
 
179
  @param[in]   d           the decimal to print
 
180
  @param[in]   fixed_prec  overall number of digits if ZEROFILL, 0 otherwise
 
181
  @param[in]   fixed_dec   number of decimal places (if fixed_prec != 0)
 
182
  @param[in]   filler      what char to pad with (ZEROFILL et al.)
 
183
  @param[out]  *str        where to store the resulting string
 
184
 
 
185
  @return error coce
 
186
    @retval E_DEC_OK
 
187
    @retval E_DEC_TRUNCATED
 
188
    @retval E_DEC_OVERFLOW
 
189
    @retval E_DEC_OOM
 
190
*/
 
191
 
 
192
int my_decimal2string(uint32_t mask, const my_decimal *d,
 
193
                      uint32_t fixed_prec, uint32_t fixed_dec,
 
194
                      char filler, String *str)
 
195
{
 
196
  /*
 
197
    Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
 
198
    holds true iff the type is also ZEROFILL, which in turn implies
 
199
    UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
 
200
    the user requested, plus one for a possible decimal point, plus
 
201
    one if the user only wanted decimal places, but we force a leading
 
202
    zero on them. Because the type is implicitly UNSIGNED, we do not
 
203
    need to reserve a character for the sign. For all other cases,
 
204
    fixed_prec will be 0, and my_decimal_string_length() will be called
 
205
    instead to calculate the required size of the buffer.
 
206
  */
 
207
  int length= (fixed_prec
 
208
               ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
 
209
               : my_decimal_string_length(d));
 
210
  int result;
 
211
  if (str->alloc(length))
 
212
    return check_result(mask, E_DEC_OOM);
 
213
  result= decimal2string((decimal_t*) d, (char*) str->ptr(),
 
214
                         &length, (int)fixed_prec, fixed_dec,
 
215
                         filler);
 
216
  str->length(length);
 
217
  return check_result(mask, result);
 
218
}
 
219
 
 
220
 
 
221
/*
 
222
  Convert from decimal to binary representation
 
223
 
 
224
  SYNOPSIS
 
225
    my_decimal2binary()
 
226
    mask        error processing mask
 
227
    d           number for conversion
 
228
    bin         pointer to buffer where to write result
 
229
    prec        overall number of decimal digits
 
230
    scale       number of decimal digits after decimal point
 
231
 
 
232
  NOTE
 
233
    Before conversion we round number if it need but produce truncation
 
234
    error in this case
 
235
 
 
236
  RETURN
 
237
    E_DEC_OK
 
238
    E_DEC_TRUNCATED
 
239
    E_DEC_OVERFLOW
 
240
*/
 
241
 
 
242
int my_decimal2binary(uint32_t mask, const my_decimal *d, unsigned char *bin, int prec,
 
243
                      int scale)
 
244
{
 
245
  int err1= E_DEC_OK, err2;
 
246
  my_decimal rounded;
 
247
  my_decimal2decimal(d, &rounded);
 
248
  rounded.frac= decimal_actual_fraction(&rounded);
 
249
  if (scale < rounded.frac)
 
250
  {
 
251
    err1= E_DEC_TRUNCATED;
 
252
    /* decimal_round can return only E_DEC_TRUNCATED */
 
253
    decimal_round(&rounded, &rounded, scale, HALF_UP);
 
254
  }
 
255
  err2= decimal2bin(&rounded, bin, prec, scale);
 
256
  if (!err2)
 
257
    err2= err1;
 
258
  return check_result(mask, err2);
 
259
}
 
260
 
 
261
 
 
262
/*
 
263
  Convert string for decimal when string can be in some multibyte charset
 
264
 
 
265
  SYNOPSIS
 
266
    str2my_decimal()
 
267
    mask            error processing mask
 
268
    from            string to process
 
269
    length          length of given string
 
270
    charset         charset of given string
 
271
    decimal_value   buffer for result storing
 
272
 
 
273
  RESULT
 
274
    E_DEC_OK
 
275
    E_DEC_TRUNCATED
 
276
    E_DEC_OVERFLOW
 
277
    E_DEC_BAD_NUM
 
278
    E_DEC_OOM
 
279
*/
 
280
 
 
281
int str2my_decimal(uint32_t mask, const char *from, uint32_t length,
 
282
                   const CHARSET_INFO * charset, my_decimal *decimal_value)
 
283
{
 
284
  char *end, *from_end;
 
285
  int err;
 
286
  char buff[STRING_BUFFER_USUAL_SIZE];
 
287
  String tmp(buff, sizeof(buff), &my_charset_bin);
 
288
  if (charset->mbminlen > 1)
 
289
  {
 
290
    uint32_t dummy_errors;
 
291
    tmp.copy(from, length, charset, &my_charset_utf8_general_ci, &dummy_errors);
 
292
    from= tmp.ptr();
 
293
    length=  tmp.length();
 
294
    charset= &my_charset_bin;
 
295
  }
 
296
  from_end= end= (char*) from+length;
 
297
  err= string2decimal((char *)from, (decimal_t*) decimal_value, &end);
 
298
  if (end != from_end && !err)
 
299
  {
 
300
    /* Give warning if there is something other than end space */
 
301
    for ( ; end < from_end; end++)
 
302
    {
 
303
      if (!my_isspace(&my_charset_utf8_general_ci, *end))
 
304
      {
 
305
        err= E_DEC_TRUNCATED;
 
306
        break;
 
307
      }
 
308
    }
 
309
  }
 
310
  check_result_and_overflow(mask, err, decimal_value);
 
311
  return err;
 
312
}
 
313
 
 
314
 
 
315
my_decimal *date2my_decimal(DRIZZLE_TIME *ltime, my_decimal *dec)
 
316
{
 
317
  int64_t date;
 
318
  date = (ltime->year*100L + ltime->month)*100L + ltime->day;
 
319
  if (ltime->time_type > DRIZZLE_TIMESTAMP_DATE)
 
320
    date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
 
321
  if (int2my_decimal(E_DEC_FATAL_ERROR, date, false, dec))
 
322
    return dec;
 
323
  if (ltime->second_part)
 
324
  {
 
325
    dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
 
326
    dec->frac= 6;
 
327
  }
 
328
  return dec;
 
329
}
 
330
 
 
331
 
 
332
void my_decimal_trim(uint32_t *precision, uint32_t *scale)
 
333
{
 
334
  if (!(*precision) && !(*scale))
 
335
  {
 
336
    *precision= 10;
 
337
    *scale= 0;
 
338
    return;
 
339
  }
 
340
}
 
341
 
120
342
 
121
343
/*
122
344
  Internally decimal numbers are stored base 10^9 (see DIG_BASE below)
236
458
  } while (0)
237
459
 
238
460
 
 
461
 
239
462
/*
240
463
  Get maximum value for given precision and scale
241
464