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/tds/convert.h>
32 : #include <freetds/bytes.h>
33 : #include <freetds/windows.h>
34 : #include <stdlib.h>
35 :
36 : /**
37 : * tds_numeric_bytes_per_prec is indexed by precision and will
38 : * tell us the number of bytes required to store the specified
39 : * precision (with the sign).
40 : * Support precision up to 77 digits
41 : */
42 : const uint8_t tds_numeric_bytes_per_prec[] = {
43 : /*
44 : * precision can't be 0 but using a value > 0 assure no
45 : * core if for some bug it's 0...
46 : */
47 : 1,
48 : 2, 2, 3, 3, 4, 4, 4, 5, 5,
49 : 6, 6, 6, 7, 7, 8, 8, 9, 9, 9,
50 : 10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
51 : 14, 14, 15, 15, 16, 16, 16, 17, 17, 18,
52 : 18, 19, 19, 19, 20, 20, 21, 21, 21, 22,
53 : 22, 23, 23, 24, 24, 24, 25, 25, 26, 26,
54 : 26, 27, 27, 28, 28, 28, 29, 29, 30, 30,
55 : 31, 31, 31, 32, 32, 33, 33, 33
56 : };
57 :
58 : TDS_COMPILE_CHECK(maxprecision,
59 : MAXPRECISION < TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec) );
60 :
61 : /*
62 : * money is a special case of numeric really...that why its here
63 : */
64 : char *
65 2006 : tds_money_to_string(TDS_INT8 money, char *s, bool use_2_digits)
66 : {
67 : TDS_UINT8 n;
68 : char *p;
69 :
70 2006 : p = s;
71 2006 : if (money < 0) {
72 450 : *p++ = '-';
73 : /* we use unsigned because this causes arithmetic problem for -2^63 */
74 450 : n = (TDS_UINT8) - money;
75 : } else {
76 1556 : n = (TDS_UINT8) money;
77 : }
78 : /* if machine is 64 bit you do not need to split n */
79 2006 : if (use_2_digits) {
80 0 : n = (n+ 50) / 100;
81 0 : sprintf(p, "%" PRIu64 ".%02u", n / 100u, (unsigned) (n % 100u));
82 : } else {
83 2006 : sprintf(p, "%" PRIu64 ".%04u", n / 10000u, (unsigned) (n % 10000u));
84 : }
85 2006 : return s;
86 : }
87 :
88 : /**
89 : * @return <0 if error
90 : */
91 : TDS_INT
92 13096 : tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s)
93 : {
94 : const unsigned char *number;
95 :
96 : unsigned int packet[sizeof(numeric->array) / 2];
97 : unsigned int *pnum, *packet_start;
98 13096 : unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet);
99 :
100 : unsigned int packet10k[(MAXPRECISION + 3) / 4];
101 : unsigned int *p;
102 :
103 : int num_bytes;
104 : unsigned int remainder, n, i, m;
105 :
106 : /* a bit of debug */
107 : #if ENABLE_EXTRA_CHECKS
108 13096 : memset(packet, 0x55, sizeof(packet));
109 13096 : memset(packet10k, 0x55, sizeof(packet10k));
110 : #endif
111 :
112 13096 : if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
113 : return TDS_CONVERT_FAIL;
114 :
115 : /* set sign */
116 13096 : if (numeric->array[0] == 1)
117 5098 : *s++ = '-';
118 :
119 : /* put number in a 16bit array */
120 13096 : number = numeric->array;
121 13096 : num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
122 :
123 13096 : n = num_bytes - 1;
124 13096 : pnum = packet_end;
125 66012 : for (; n > 1; n -= 2)
126 52916 : *--pnum = TDS_GET_UA2BE(&number[n - 1]);
127 13096 : if (n == 1)
128 12022 : *--pnum = number[n];
129 : /* remove leading zeroes */
130 49172 : while (!*pnum) {
131 36246 : ++pnum;
132 : /* we consumed all numbers, it's a zero */
133 36246 : if (pnum == packet_end) {
134 170 : *s++ = '0';
135 170 : if (numeric->scale) {
136 10 : *s++ = '.';
137 10 : i = numeric->scale;
138 : do {
139 40 : *s++ = '0';
140 40 : } while (--i);
141 : }
142 170 : *s = 0;
143 170 : return 1;
144 : }
145 : }
146 : packet_start = pnum;
147 :
148 : /* transform 2^16 base number in 10^4 base number */
149 46858 : for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
150 33932 : pnum = packet_start;
151 33932 : n = *pnum;
152 33932 : remainder = n % 10000u;
153 33932 : if (!(*pnum++ = (n / 10000u)))
154 28692 : packet_start = pnum;
155 35620 : for (; pnum != packet_end; ++pnum) {
156 35620 : n = remainder * (256u * 256u) + *pnum;
157 35620 : remainder = n % 10000u;
158 35620 : *pnum = n / 10000u;
159 : }
160 33932 : *--p = remainder;
161 : }
162 :
163 : /* transform to 10 base number and output */
164 12926 : i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p); /* current digit */
165 : /* skip leading zeroes */
166 12926 : n = 1000;
167 12926 : remainder = *p;
168 46618 : while (remainder < n)
169 20766 : n /= 10, --i;
170 12926 : if (i <= numeric->scale) {
171 40 : *s++ = '0';
172 40 : *s++ = '.';
173 40 : m = i;
174 160 : while (m < numeric->scale)
175 80 : *s++ = '0', ++m;
176 : }
177 : for (;;) {
178 114962 : *s++ = (remainder / n) + '0';
179 114962 : --i;
180 114962 : remainder %= n;
181 114962 : n /= 10;
182 114962 : if (!n) {
183 33932 : n = 1000;
184 33932 : if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
185 : break;
186 21006 : remainder = *p;
187 : }
188 102036 : if (i == numeric->scale)
189 1476 : *s++ = '.';
190 : }
191 12926 : *s = 0;
192 :
193 12926 : return 1;
194 : }
195 :
196 : #define TDS_WORD uint32_t
197 : #define TDS_DWORD uint64_t
198 : #define TDS_WORD_DDIGIT 9
199 :
200 : /* include to check limits */
201 :
202 : #include "num_limits.h"
203 :
204 : static int
205 43828 : tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
206 : {
207 : unsigned int i, len, stop;
208 43828 : const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
209 43828 : len = limit_indexes[prec+1] - limit_indexes[prec] + LIMIT_INDEXES_ADJUST;
210 43828 : stop = prec / (sizeof(TDS_WORD) * 8);
211 : /*
212 : * Now a number is
213 : * ... P[3] P[2] P[1] P[0]
214 : * while upper limit + 1 is
215 : * zeroes limit[0 .. len-1] 0[0 .. stop-1]
216 : * we must assure that number < upper limit + 1
217 : */
218 43828 : if (packet_len >= len + stop) {
219 : /* higher packets must be zero */
220 33500 : for (i = packet_len; --i >= len + stop; )
221 9550 : if (packet[i] > 0)
222 : return TDS_CONVERT_OVERFLOW;
223 : /* test limit */
224 0 : for (;; --i, ++limit) {
225 23950 : if (i <= stop) {
226 : /* last must be >= not > */
227 20070 : if (packet[i] >= *limit)
228 : return TDS_CONVERT_OVERFLOW;
229 : break;
230 : }
231 3880 : if (packet[i] > *limit)
232 : return TDS_CONVERT_OVERFLOW;
233 1160 : if (packet[i] < *limit)
234 : break;
235 : }
236 : }
237 22748 : return 0;
238 : }
239 :
240 : #undef USE_128_MULTIPLY
241 : #if defined(__GNUC__) && SIZEOF___INT128 > 0
242 : #define USE_128_MULTIPLY 1
243 : #undef __umulh
244 : #define __umulh(multiplier, multiplicand) \
245 : ((uint64_t) ((((unsigned __int128) (multiplier)) * (multiplicand)) >> 64))
246 : #endif
247 : #if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM64))
248 : #include <intrin.h>
249 : #define USE_128_MULTIPLY 1
250 : #endif
251 :
252 : #undef USE_I386_DIVIDE
253 : #undef USE_64_MULTIPLY
254 : #ifndef USE_128_MULTIPLY
255 : # if defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
256 : # define USE_I386_DIVIDE 1
257 : # else
258 : # define USE_64_MULTIPLY
259 : # endif
260 : #endif
261 :
262 : TDS_INT
263 80422 : tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale)
264 : {
265 : #define TDS_WORD_BITS (8 * sizeof(TDS_WORD))
266 : static const TDS_WORD factors[] = {
267 : 1, 10, 100, 1000, 10000,
268 : 100000, 1000000, 10000000, 100000000, 1000000000
269 : };
270 : #ifndef USE_I386_DIVIDE
271 : /* These numbers are computed as
272 : * (2 ** (reverse_dividers_shift[i] + 64)) / (10 ** i) + 1
273 : * (** is power).
274 : * The shifts are computed to make sure the multiplication error
275 : * does not cause a wrong result.
276 : *
277 : * See also misc/reverse_divisor script.
278 : */
279 : static const TDS_DWORD reverse_dividers[] = {
280 : 1 /* not used */,
281 : UINT64_C(1844674407370955162),
282 : UINT64_C(184467440737095517),
283 : UINT64_C(18446744073709552),
284 : UINT64_C(1844674407370956),
285 : UINT64_C(737869762948383),
286 : UINT64_C(2361183241434823),
287 : UINT64_C(15111572745182865),
288 : UINT64_C(48357032784585167),
289 : UINT64_C(1237940039285380275),
290 : };
291 : static const uint8_t reverse_dividers_shift[] = {
292 : 0 /* not used */,
293 : 0,
294 : 0,
295 : 0,
296 : 0,
297 : 2,
298 : 7,
299 : 13,
300 : 18,
301 : 26,
302 : };
303 : #endif
304 :
305 : TDS_WORD packet[(sizeof(numeric->array) - 1) / sizeof(TDS_WORD)];
306 :
307 : unsigned int i, packet_len;
308 : int scale_diff, bytes;
309 :
310 80422 : if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
311 : return TDS_CONVERT_FAIL;
312 :
313 80422 : if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
314 : return TDS_CONVERT_FAIL;
315 :
316 80422 : scale_diff = new_scale - numeric->scale;
317 80422 : if (scale_diff == 0 && new_prec >= numeric->precision) {
318 29892 : i = tds_numeric_bytes_per_prec[new_prec] - tds_numeric_bytes_per_prec[numeric->precision];
319 29892 : if (i > 0) {
320 12280 : memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
321 12280 : memset(numeric->array + 1, 0, i);
322 : }
323 29892 : numeric->precision = new_prec;
324 29892 : return sizeof(TDS_NUMERIC);
325 : }
326 :
327 : /* package number */
328 50530 : bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
329 50530 : i = 0;
330 : do {
331 : /*
332 : * note that if bytes are smaller we have a small buffer
333 : * overflow in numeric->array however is not a problem
334 : * cause overflow occurs in numeric and number is fixed below
335 : */
336 147530 : packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
337 147530 : ++i;
338 147530 : } while ( (bytes -= sizeof(TDS_WORD)) > 0);
339 : /* fix last packet */
340 50530 : if (bytes < 0)
341 49642 : packet[i-1] &= 0xffffffffu >> (8 * -bytes);
342 130530 : while (i > 1 && packet[i-1] == 0)
343 : --i;
344 50530 : packet_len = i;
345 :
346 50530 : if (scale_diff >= 0) {
347 : /* check overflow before multiply */
348 43428 : if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
349 : return TDS_CONVERT_OVERFLOW;
350 :
351 22598 : if (scale_diff == 0) {
352 15344 : i = tds_numeric_bytes_per_prec[numeric->precision] - tds_numeric_bytes_per_prec[new_prec];
353 15344 : if (i > 0)
354 15344 : memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
355 15344 : numeric->precision = new_prec;
356 15344 : return sizeof(TDS_NUMERIC);
357 : }
358 :
359 : /* multiply */
360 : do {
361 : /* multiply by at maximun TDS_WORD_DDIGIT */
362 7274 : unsigned int n = TDS_MIN(scale_diff, TDS_WORD_DDIGIT);
363 7274 : TDS_WORD factor = factors[n];
364 7274 : TDS_WORD carry = 0;
365 7274 : scale_diff -= n;
366 15318 : for (i = 0; i < packet_len; ++i) {
367 8044 : TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
368 8044 : packet[i] = (TDS_WORD) n;
369 8044 : carry = n >> TDS_WORD_BITS;
370 : }
371 : /* here we can expand number safely cause we know that it can't overflow */
372 7274 : if (carry)
373 850 : packet[packet_len++] = carry;
374 7274 : } while (scale_diff > 0);
375 : } else {
376 : /* check overflow */
377 7102 : if (new_prec - scale_diff < numeric->precision)
378 400 : if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
379 : return TDS_CONVERT_OVERFLOW;
380 :
381 : /* divide */
382 6852 : scale_diff = -scale_diff;
383 : do {
384 6952 : unsigned int n = TDS_MIN(scale_diff, TDS_WORD_DDIGIT);
385 6952 : TDS_WORD factor = factors[n];
386 6952 : TDS_WORD borrow = 0;
387 : #if defined(USE_128_MULTIPLY)
388 6952 : TDS_DWORD reverse_divider = reverse_dividers[n];
389 6952 : uint8_t shift = reverse_dividers_shift[n];
390 : #elif defined(USE_64_MULTIPLY)
391 : TDS_WORD reverse_divider_low = (TDS_WORD) reverse_dividers[n];
392 : TDS_WORD reverse_divider_high = (TDS_WORD) (reverse_dividers[n] >> TDS_WORD_BITS);
393 : uint8_t shift = reverse_dividers_shift[n];
394 : #endif
395 6952 : scale_diff -= n;
396 22596 : for (i = packet_len; i > 0; ) {
397 : #ifdef USE_I386_DIVIDE
398 : --i;
399 : /* For different reasons this code is still here.
400 : * But mainly because although compilers do wonderful things this is hard to get.
401 : * One of the reason is that it's hard to understand that the double-precision division
402 : * result will fit into 32-bit.
403 : */
404 : __asm__ ("divl %4": "=a"(packet[i]), "=d"(borrow): "0"(packet[i]), "1"(borrow), "r"(factor));
405 : #else
406 8692 : TDS_DWORD n = (((TDS_DWORD) borrow) << TDS_WORD_BITS) + packet[--i];
407 : #if defined(USE_128_MULTIPLY)
408 8692 : TDS_DWORD quotient = __umulh(n, reverse_divider);
409 : #else
410 : TDS_DWORD mul1 = (TDS_DWORD) packet[i] * reverse_divider_low;
411 : TDS_DWORD mul2 = (TDS_DWORD) borrow * reverse_divider_low + (mul1 >> TDS_WORD_BITS);
412 : TDS_DWORD mul3 = (TDS_DWORD) packet[i] * reverse_divider_high;
413 : TDS_DWORD quotient = (TDS_DWORD) borrow * reverse_divider_high + (mul3 >> TDS_WORD_BITS);
414 : quotient += (mul2 + (mul3 & 0xffffffffu)) >> TDS_WORD_BITS;
415 : #endif
416 8692 : quotient >>= shift;
417 8692 : packet[i] = (TDS_WORD) quotient;
418 8692 : borrow = (TDS_WORD) (n - quotient * factor);
419 : #endif
420 : }
421 6952 : } while (scale_diff > 0);
422 : }
423 :
424 : /* back to our format */
425 14106 : numeric->precision = new_prec;
426 14106 : numeric->scale = new_scale;
427 14106 : bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
428 36692 : for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
429 22586 : packet[i] = 0;
430 25726 : for (i = 0; bytes >= (int) sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
431 25726 : TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
432 : }
433 :
434 14106 : if (bytes) {
435 13440 : TDS_WORD remainder = packet[i];
436 : do {
437 13790 : numeric->array[bytes] = (TDS_UCHAR) remainder;
438 13790 : remainder >>= 8;
439 13790 : } while (--bytes);
440 : }
441 :
442 : return sizeof(TDS_NUMERIC);
443 : }
444 :
|