~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/my_decimal.cc

Fixed the clock_gettime test.

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