NCBI C++ ToolKit
numeric.c
Go to the documentation of this file.

Go to the SVN repository for this file.

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  */
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,
59 
60 /*
61  * money is a special case of numeric really...that why its here
62  */
63 char *
64 tds_money_to_string(const TDS_MONEY * money, char *s)
65 {
66  int frac;
67  TDS_INT8 mymoney;
68  TDS_UINT8 n;
69  char *p;
70 
71  /* sometimes money it's only 4-byte aligned so always compute 64-bit */
72  mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
73 
74  p = s;
75  if (mymoney < 0) {
76  *p++ = '-';
77  /* we use unsigned cause this cause arithmetic problem for -2^63*/
78  n = -mymoney;
79  } else {
80  n = mymoney;
81  }
82  n = (n + 50) / 100;
83  frac = (int) (n % 100);
84  n /= 100;
85  /* if machine is 64 bit you do not need to split n */
86  sprintf(p, "%" PRId64 ".%02d", n, frac);
87  return s;
88 }
89 
90 /**
91  * @return <0 if error
92  */
93 TDS_INT
94 tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s)
95 {
96  const unsigned char *number;
97 
98  unsigned int packet[sizeof(numeric->array) / 2];
99  unsigned int *pnum, *packet_start;
100  unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet);
101 
102  unsigned int packet10k[(MAXPRECISION + 3) / 4];
103  unsigned int *p;
104 
105  int num_bytes;
106  unsigned int remainder, n, i, m;
107 
108  /* a bit of debug */
109 #if ENABLE_EXTRA_CHECKS
110  memset(packet, 0x55, sizeof(packet));
111  memset(packet10k, 0x55, sizeof(packet10k));
112 #endif
113 
114  if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
115  return TDS_CONVERT_FAIL;
116 
117  /* set sign */
118  if (numeric->array[0] == 1)
119  *s++ = '-';
120 
121  /* put number in a 16bit array */
122  number = numeric->array;
123  num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
124 
125  n = num_bytes - 1;
126  pnum = packet_end;
127  for (; n > 1; n -= 2)
128  *--pnum = TDS_GET_UA2BE(&number[n - 1]);
129  if (n == 1)
130  *--pnum = number[n];
131  while (!*pnum) {
132  ++pnum;
133  if (pnum == packet_end) {
134  *s++ = '0';
135  if (numeric->scale) {
136  *s++ = '.';
137  i = numeric->scale;
138  do {
139  *s++ = '0';
140  } while (--i);
141  }
142  *s = 0;
143  return 1;
144  }
145  }
146  packet_start = pnum;
147 
148  /* transform 2^16 base number in 10^4 base number */
149  for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
150  pnum = packet_start;
151  n = *pnum;
152  remainder = n % 10000u;
153  if (!(*pnum++ = (n / 10000u)))
154  packet_start = pnum;
155  for (; pnum != packet_end; ++pnum) {
156  n = remainder * (256u * 256u) + *pnum;
157  remainder = n % 10000u;
158  *pnum = n / 10000u;
159  }
160  *--p = remainder;
161  }
162 
163  /* transform to 10 base number and output */
164  i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p); /* current digit */
165  /* skip leading zeroes */
166  n = 1000;
167  remainder = *p;
168  while (remainder < n)
169  n /= 10, --i;
170  if (i <= numeric->scale) {
171  *s++ = '0';
172  *s++ = '.';
173  m = i;
174  while (m < numeric->scale)
175  *s++ = '0', ++m;
176  }
177  for (;;) {
178  *s++ = (remainder / n) + '0';
179  --i;
180  remainder %= n;
181  n /= 10;
182  if (!n) {
183  n = 1000;
184  if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
185  break;
186  remainder = *p;
187  }
188  if (i == numeric->scale)
189  *s++ = '.';
190  }
191  *s = 0;
192 
193  return 1;
194 }
195 
196 #define TDS_WORD TDS_UINT
197 #define TDS_DWORD TDS_UINT8
198 #define TDS_WORD_DDIGIT 9
199 
200 /* include to check limits */
201 
202 #include "num_limits.h"
203 
204 static int
205 tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
206 {
207  unsigned int i, len, stop;
208  const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
210  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  if (packet_len >= len + stop) {
219  /* higher packets must be zero */
220  for (i = packet_len; --i >= len + stop; )
221  if (packet[i] > 0)
222  return TDS_CONVERT_OVERFLOW;
223  /* test limit */
224  for (;; --i, ++limit) {
225  if (i <= stop) {
226  /* last must be >= not > */
227  if (packet[i] >= *limit)
228  return TDS_CONVERT_OVERFLOW;
229  break;
230  }
231  if (packet[i] > *limit)
232  return TDS_CONVERT_OVERFLOW;
233  if (packet[i] < *limit)
234  break;
235  }
236  }
237  return 0;
238 }
239 
240 TDS_INT
241 tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale)
242 {
243  static const TDS_WORD factors[] = {
244  1, 10, 100, 1000, 10000,
245  100000, 1000000, 10000000, 100000000, 1000000000
246  };
247 
248  TDS_WORD packet[(sizeof(numeric->array) - 1) / sizeof(TDS_WORD)];
249 
250  unsigned int i, packet_len;
251  int scale_diff, bytes;
252 
253  if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
254  return TDS_CONVERT_FAIL;
255 
256  if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
257  return TDS_CONVERT_FAIL;
258 
259  scale_diff = new_scale - numeric->scale;
260  if (scale_diff == 0 && new_prec >= numeric->precision) {
262  if (i > 0) {
263  memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
264  memset(numeric->array + 1, 0, i);
265  }
266  numeric->precision = new_prec;
267  return sizeof(TDS_NUMERIC);
268  }
269 
270  /* package number */
271  bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
272  i = 0;
273  do {
274  /*
275  * note that if bytes are smaller we have a small buffer
276  * overflow in numeric->array however is not a problem
277  * cause overflow occurs in numeric and number is fixed below
278  */
279  packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
280  ++i;
281  } while ( (bytes -= sizeof(TDS_WORD)) > 0);
282  /* fix last packet */
283  if (bytes < 0)
284  packet[i-1] &= 0xffffffffu >> (8 * -bytes);
285  while (i > 1 && packet[i-1] == 0)
286  --i;
287  packet_len = i;
288 
289  if (scale_diff >= 0) {
290  /* check overflow before multiply */
291  if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
292  return TDS_CONVERT_OVERFLOW;
293 
294  if (scale_diff == 0) {
296  if (i > 0)
297  memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
298  numeric->precision = new_prec;
299  return sizeof(TDS_NUMERIC);
300  }
301 
302  /* multiply */
303  do {
304  /* multiply by at maximun TDS_WORD_DDIGIT */
305  unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
306  TDS_WORD factor = factors[n];
307  TDS_WORD carry = 0;
308  scale_diff -= n;
309  for (i = 0; i < packet_len; ++i) {
310  TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
311  packet[i] = (TDS_WORD) n;
312  carry = n >> (8 * sizeof(TDS_WORD));
313  }
314  /* here we can expand number safely cause we know that it can't overflow */
315  if (carry)
316  packet[packet_len++] = carry;
317  } while (scale_diff > 0);
318  } else {
319  /* check overflow */
320  if (new_prec - scale_diff < numeric->precision)
321  if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
322  return TDS_CONVERT_OVERFLOW;
323 
324  /* divide */
325  scale_diff = -scale_diff;
326  do {
327  unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
328  TDS_WORD factor = factors[n];
329  TDS_WORD borrow = 0;
330  scale_diff -= n;
331  for (i = packet_len; i > 0; ) {
332 #if defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
333  --i;
334  __asm__ ("divl %4": "=a"(packet[i]), "=d"(borrow): "0"(packet[i]), "1"(borrow), "r"(factor));
335 #elif defined(__WATCOMC__) && defined(DOS32X)
336  TDS_WORD Int64div32(TDS_WORD* low,TDS_WORD high,TDS_WORD factor);
337  #pragma aux Int64div32 = "mov eax, dword ptr[esi]" \
338  "div ecx" \
339  "mov dword ptr[esi], eax" \
340  parm [ESI] [EDX] [ECX] value [EDX] modify [EAX EDX];
341  borrow = Int64div32(&packet[i], borrow, factor);
342 #else
343  TDS_DWORD n = (((TDS_DWORD) borrow) << (8 * sizeof(TDS_WORD))) + packet[--i];
344  packet[i] = (TDS_WORD) (n / factor);
345  borrow = n % factor;
346 #endif
347  }
348  } while (scale_diff > 0);
349  }
350 
351  /* back to our format */
352  numeric->precision = new_prec;
353  numeric->scale = new_scale;
354  bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
355  for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
356  packet[i] = 0;
357  for (i = 0; bytes >= sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
358  TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
359  }
360 
361  if (bytes) {
362  TDS_WORD remainder = packet[i];
363  do {
364  numeric->array[bytes] = (TDS_UCHAR) remainder;
365  remainder >>= 8;
366  } while (--bytes);
367  }
368 
369  return sizeof(TDS_NUMERIC);
370 }
371 
#define TDS_GET_UA4BE(ptr)
Definition: bytes.h:72
#define TDS_GET_UA2BE(ptr)
Definition: bytes.h:57
#define TDS_PUT_UA4BE(ptr, val)
Definition: bytes.h:81
#define TDS_CONVERT_OVERFLOW
Definition: convert.h:80
#define TDS_CONVERT_FAIL
Definition: convert.h:76
static char precision
Definition: genparams.c:28
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int i
if(yy_accept[yy_current_state])
yy_size_t n
int len
#define LIMIT_INDEXES_ADJUST
Definition: num_limits.h:1
static const TDS_WORD limits[]
Definition: num_limits.h:85
static const signed char limit_indexes[79]
Definition: num_limits.h:3
#define memmove(a, b, c)
static BOOL number
Definition: pcregrep.c:193
struct tdsnumeric TDS_NUMERIC
unsigned char scale
Definition: proto.h:28
unsigned char precision
Definition: proto.h:27
unsigned char array[33]
Definition: proto.h:29
TDS_INT mnyhigh
Definition: proto.h:34
TDS_UINT mnylow
Definition: proto.h:35
#define PRId64
char * tds_money_to_string(const TDS_MONEY *money, char *s)
Definition: numeric.c:64
const int tds_numeric_bytes_per_prec[]
tds_numeric_bytes_per_prec is indexed by precision and will tell us the number of bytes required to s...
Definition: numeric.c:41
TDS_INT tds_numeric_to_string(const TDS_NUMERIC *numeric, char *s)
Definition: numeric.c:94
#define TDS_WORD_DDIGIT
Definition: numeric.c:198
#define TDS_WORD
Definition: numeric.c:196
#define TDS_DWORD
Definition: numeric.c:197
TDS_INT tds_numeric_change_prec_scale(TDS_NUMERIC *numeric, unsigned char new_prec, unsigned char new_scale)
Definition: numeric.c:241
TDS_COMPILE_CHECK(maxprecision, MAXPRECISION< TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec))
static int tds_packet_check_overflow(TDS_UINT *packet, unsigned int packet_len, unsigned int prec)
Definition: numeric.c:205
Main include file for libtds.
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
tds_sysdep_int64_type TDS_INT8
Definition: tds.h:153
unsigned char TDS_UCHAR
Definition: tds.h:145
#define TDS_VECTOR_SIZE(x)
Definition: tds.h:360
tds_sysdep_uint64_type TDS_UINT8
Definition: tds.h:154
#define MAXPRECISION
Definition: tds.h:470
Definition: proto.h:39
TDS_OLD_MONEY tdsoldmoney
Definition: proto.h:40
Modified on Fri Dec 01 04:44:53 2023 by modify_doxy.py rev. 669887