Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998-1999 Brian Bruns
3 : * Copyright (C) 2005-2015 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #if HAVE_STRING_H
27 : #include <string.h>
28 : #endif /* HAVE_STRING_H */
29 :
30 : #include <freetds/tds.h>
31 : #include <freetds/convert.h>
32 : #include <freetds/bytes.h>
33 : #include <stdlib.h>
34 :
35 : /**
36 : * tds_numeric_bytes_per_prec is indexed by precision and will
37 : * tell us the number of bytes required to store the specified
38 : * precision (with the sign).
39 : * Support precision up to 77 digits
40 : */
41 : const int tds_numeric_bytes_per_prec[] = {
42 : /*
43 : * precision can't be 0 but using a value > 0 assure no
44 : * core if for some bug it's 0...
45 : */
46 : 1,
47 : 2, 2, 3, 3, 4, 4, 4, 5, 5,
48 : 6, 6, 6, 7, 7, 8, 8, 9, 9, 9,
49 : 10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
50 : 14, 14, 15, 15, 16, 16, 16, 17, 17, 18,
51 : 18, 19, 19, 19, 20, 20, 21, 21, 21, 22,
52 : 22, 23, 23, 24, 24, 24, 25, 25, 26, 26,
53 : 26, 27, 27, 28, 28, 28, 29, 29, 30, 30,
54 : 31, 31, 31, 32, 32, 33, 33, 33
55 : };
56 :
57 : TDS_COMPILE_CHECK(maxprecision,
58 : MAXPRECISION < TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec) );
59 :
60 : /*
61 : * money is a special case of numeric really...that why its here
62 : */
63 : char *
64 1592 : tds_money_to_string(const TDS_MONEY * money, char *s, bool use_2_digits)
65 : {
66 : TDS_INT8 mymoney;
67 : TDS_UINT8 n;
68 : char *p;
69 :
70 : /* sometimes money it's only 4-byte aligned so always compute 64-bit */
71 1592 : mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
72 :
73 1592 : p = s;
74 1592 : if (mymoney < 0) {
75 360 : *p++ = '-';
76 : /* we use unsigned cause this cause arithmetic problem for -2^63*/
77 360 : n = -mymoney;
78 : } else {
79 1232 : n = mymoney;
80 : }
81 : /* if machine is 64 bit you do not need to split n */
82 1592 : if (use_2_digits) {
83 0 : n = (n+ 50) / 100;
84 0 : sprintf(p, "%" PRIu64 ".%02u", n / 100u, (unsigned) (n % 100u));
85 : } else {
86 1592 : sprintf(p, "%" PRIu64 ".%04u", n / 10000u, (unsigned) (n % 10000u));
87 : }
88 1592 : return s;
89 : }
90 :
91 : /**
92 : * @return <0 if error
93 : */
94 : TDS_INT
95 10172 : tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s)
96 : {
97 : const unsigned char *number;
98 :
99 : unsigned int packet[sizeof(numeric->array) / 2];
100 : unsigned int *pnum, *packet_start;
101 10172 : unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet);
102 :
103 : unsigned int packet10k[(MAXPRECISION + 3) / 4];
104 : unsigned int *p;
105 :
106 : int num_bytes;
107 : unsigned int remainder, n, i, m;
108 :
109 : /* a bit of debug */
110 : #if ENABLE_EXTRA_CHECKS
111 10172 : memset(packet, 0x55, sizeof(packet));
112 10172 : memset(packet10k, 0x55, sizeof(packet10k));
113 : #endif
114 :
115 10172 : if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
116 : return TDS_CONVERT_FAIL;
117 :
118 : /* set sign */
119 10172 : if (numeric->array[0] == 1)
120 4078 : *s++ = '-';
121 :
122 : /* put number in a 16bit array */
123 10172 : number = numeric->array;
124 10172 : num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
125 :
126 10172 : n = num_bytes - 1;
127 10172 : pnum = packet_end;
128 50774 : for (; n > 1; n -= 2)
129 40602 : *--pnum = TDS_GET_UA2BE(&number[n - 1]);
130 10172 : if (n == 1)
131 9318 : *--pnum = number[n];
132 38224 : while (!*pnum) {
133 28188 : ++pnum;
134 28188 : if (pnum == packet_end) {
135 136 : *s++ = '0';
136 136 : if (numeric->scale) {
137 8 : *s++ = '.';
138 8 : i = numeric->scale;
139 : do {
140 32 : *s++ = '0';
141 32 : } while (--i);
142 : }
143 136 : *s = 0;
144 136 : return 1;
145 : }
146 : }
147 : packet_start = pnum;
148 :
149 : /* transform 2^16 base number in 10^4 base number */
150 35718 : for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
151 25682 : pnum = packet_start;
152 25682 : n = *pnum;
153 25682 : remainder = n % 10000u;
154 25682 : if (!(*pnum++ = (n / 10000u)))
155 21732 : packet_start = pnum;
156 25866 : for (; pnum != packet_end; ++pnum) {
157 25866 : n = remainder * (256u * 256u) + *pnum;
158 25866 : remainder = n % 10000u;
159 25866 : *pnum = n / 10000u;
160 : }
161 25682 : *--p = remainder;
162 : }
163 :
164 : /* transform to 10 base number and output */
165 10036 : i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p); /* current digit */
166 : /* skip leading zeroes */
167 10036 : n = 1000;
168 10036 : remainder = *p;
169 36450 : while (remainder < n)
170 16378 : n /= 10, --i;
171 10036 : if (i <= numeric->scale) {
172 32 : *s++ = '0';
173 32 : *s++ = '.';
174 32 : m = i;
175 128 : while (m < numeric->scale)
176 64 : *s++ = '0', ++m;
177 : }
178 : for (;;) {
179 86350 : *s++ = (remainder / n) + '0';
180 86350 : --i;
181 86350 : remainder %= n;
182 86350 : n /= 10;
183 86350 : if (!n) {
184 25682 : n = 1000;
185 25682 : if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
186 : break;
187 15646 : remainder = *p;
188 : }
189 76314 : if (i == numeric->scale)
190 878 : *s++ = '.';
191 : }
192 10036 : *s = 0;
193 :
194 10036 : return 1;
195 : }
196 :
197 : #define TDS_WORD uint32_t
198 : #define TDS_DWORD uint64_t
199 : #define TDS_WORD_DDIGIT 9
200 :
201 : /* include to check limits */
202 :
203 : #include "num_limits.h"
204 :
205 : static int
206 31326 : tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
207 : {
208 : unsigned int i, len, stop;
209 31326 : const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
210 31326 : len = limit_indexes[prec+1] - limit_indexes[prec] + LIMIT_INDEXES_ADJUST;
211 31326 : stop = prec / (sizeof(TDS_WORD) * 8);
212 : /*
213 : * Now a number is
214 : * ... P[3] P[2] P[1] P[0]
215 : * while upper limit + 1 is
216 : * zeroes limit[0 .. len-1] 0[0 .. stop-1]
217 : * we must assure that number < upper limit + 1
218 : */
219 31326 : if (packet_len >= len + stop) {
220 : /* higher packets must be zero */
221 23066 : for (i = packet_len; --i >= len + stop; )
222 6456 : if (packet[i] > 0)
223 : return TDS_CONVERT_OVERFLOW;
224 : /* test limit */
225 0 : for (;; --i, ++limit) {
226 16610 : if (i <= stop) {
227 : /* last must be >= not > */
228 13506 : if (packet[i] >= *limit)
229 : return TDS_CONVERT_OVERFLOW;
230 : break;
231 : }
232 3104 : if (packet[i] > *limit)
233 : return TDS_CONVERT_OVERFLOW;
234 928 : if (packet[i] < *limit)
235 : break;
236 : }
237 : }
238 17150 : return 0;
239 : }
240 :
241 : TDS_INT
242 60098 : tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale)
243 : {
244 : static const TDS_WORD factors[] = {
245 : 1, 10, 100, 1000, 10000,
246 : 100000, 1000000, 10000000, 100000000, 1000000000
247 : };
248 :
249 : TDS_WORD packet[(sizeof(numeric->array) - 1) / sizeof(TDS_WORD)];
250 :
251 : unsigned int i, packet_len;
252 : int scale_diff, bytes;
253 :
254 60098 : if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
255 : return TDS_CONVERT_FAIL;
256 :
257 60098 : if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
258 : return TDS_CONVERT_FAIL;
259 :
260 60098 : scale_diff = new_scale - numeric->scale;
261 60098 : if (scale_diff == 0 && new_prec >= numeric->precision) {
262 23550 : i = tds_numeric_bytes_per_prec[new_prec] - tds_numeric_bytes_per_prec[numeric->precision];
263 23550 : if (i > 0) {
264 9488 : memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
265 9488 : memset(numeric->array + 1, 0, i);
266 : }
267 23550 : numeric->precision = new_prec;
268 23550 : return sizeof(TDS_NUMERIC);
269 : }
270 :
271 : /* package number */
272 36548 : bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
273 36548 : i = 0;
274 : do {
275 : /*
276 : * note that if bytes are smaller we have a small buffer
277 : * overflow in numeric->array however is not a problem
278 : * cause overflow occurs in numeric and number is fixed below
279 : */
280 106314 : packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
281 106314 : ++i;
282 106314 : } while ( (bytes -= sizeof(TDS_WORD)) > 0);
283 : /* fix last packet */
284 36548 : if (bytes < 0)
285 35856 : packet[i-1] &= 0xffffffffu >> (8 * -bytes);
286 94346 : while (i > 1 && packet[i-1] == 0)
287 : --i;
288 36548 : packet_len = i;
289 :
290 36548 : if (scale_diff >= 0) {
291 : /* check overflow before multiply */
292 31022 : if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
293 : return TDS_CONVERT_OVERFLOW;
294 :
295 17046 : if (scale_diff == 0) {
296 11266 : i = tds_numeric_bytes_per_prec[numeric->precision] - tds_numeric_bytes_per_prec[new_prec];
297 11266 : if (i > 0)
298 11266 : memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
299 11266 : numeric->precision = new_prec;
300 11266 : return sizeof(TDS_NUMERIC);
301 : }
302 :
303 : /* multiply */
304 : do {
305 : /* multiply by at maximun TDS_WORD_DDIGIT */
306 5796 : unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
307 5796 : TDS_WORD factor = factors[n];
308 5796 : TDS_WORD carry = 0;
309 5796 : scale_diff -= n;
310 12208 : for (i = 0; i < packet_len; ++i) {
311 6412 : TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
312 6412 : packet[i] = (TDS_WORD) n;
313 6412 : carry = n >> (8 * sizeof(TDS_WORD));
314 : }
315 : /* here we can expand number safely cause we know that it can't overflow */
316 5796 : if (carry)
317 680 : packet[packet_len++] = carry;
318 5796 : } while (scale_diff > 0);
319 : } else {
320 : /* check overflow */
321 5526 : if (new_prec - scale_diff < numeric->precision)
322 304 : if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
323 : return TDS_CONVERT_OVERFLOW;
324 :
325 : /* divide */
326 5326 : scale_diff = -scale_diff;
327 : do {
328 5342 : unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
329 5342 : TDS_WORD factor = factors[n];
330 5342 : TDS_WORD borrow = 0;
331 5342 : scale_diff -= n;
332 17018 : for (i = packet_len; i > 0; ) {
333 : #if defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
334 : --i;
335 : __asm__ ("divl %4": "=a"(packet[i]), "=d"(borrow): "0"(packet[i]), "1"(borrow), "r"(factor));
336 : #elif defined(__WATCOMC__) && defined(DOS32X)
337 : TDS_WORD Int64div32(TDS_WORD* low,TDS_WORD high,TDS_WORD factor);
338 : #pragma aux Int64div32 = "mov eax, dword ptr[esi]" \
339 : "div ecx" \
340 : "mov dword ptr[esi], eax" \
341 : parm [ESI] [EDX] [ECX] value [EDX] modify [EAX EDX];
342 : borrow = Int64div32(&packet[i], borrow, factor);
343 : #else
344 6334 : TDS_DWORD n = (((TDS_DWORD) borrow) << (8 * sizeof(TDS_WORD))) + packet[--i];
345 6334 : packet[i] = (TDS_WORD) (n / factor);
346 6334 : borrow = n % factor;
347 : #endif
348 : }
349 5342 : } while (scale_diff > 0);
350 : }
351 :
352 : /* back to our format */
353 11106 : numeric->precision = new_prec;
354 11106 : numeric->scale = new_scale;
355 11106 : bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
356 29000 : for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
357 17894 : packet[i] = 0;
358 20134 : for (i = 0; bytes >= sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
359 20134 : TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
360 : }
361 :
362 11106 : if (bytes) {
363 10594 : TDS_WORD remainder = packet[i];
364 : do {
365 10858 : numeric->array[bytes] = (TDS_UCHAR) remainder;
366 10858 : remainder >>= 8;
367 10858 : } while (--bytes);
368 : }
369 :
370 : return sizeof(TDS_NUMERIC);
371 : }
372 :
|