Age Owner Branch data TLA Line data Source code
1 : : /* src/interfaces/ecpg/pgtypeslib/numeric.c */
2 : :
3 : : #include "postgres_fe.h"
4 : :
5 : : #include <ctype.h>
6 : : #include <float.h>
7 : : #include <limits.h>
8 : :
9 : : #include "pgtypes_error.h"
10 : : #include "pgtypes_numeric.h"
11 : : #include "pgtypeslib_extern.h"
12 : :
13 : : #define Max(x, y) ((x) > (y) ? (x) : (y))
14 : : #define Min(x, y) ((x) < (y) ? (x) : (y))
15 : :
16 : : #define init_var(v) memset(v,0,sizeof(numeric))
17 : :
18 : : #define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))
19 : : #define digitbuf_free(buf) free(buf)
20 : :
21 : :
22 : : /* ----------
23 : : * alloc_var() -
24 : : *
25 : : * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
26 : : * ----------
27 : : */
28 : : static int
6718 bruce@momjian.us 29 :CBC 11714 : alloc_var(numeric *var, int ndigits)
30 : : {
7700 meskes@postgresql.or 31 : 11714 : digitbuf_free(var->buf);
32 : 11714 : var->buf = digitbuf_alloc(ndigits + 1);
33 [ - + ]: 11714 : if (var->buf == NULL)
7700 meskes@postgresql.or 34 :UBC 0 : return -1;
7700 meskes@postgresql.or 35 :CBC 11714 : var->buf[0] = 0;
36 : 11714 : var->digits = var->buf + 1;
37 : 11714 : var->ndigits = ndigits;
38 : 11714 : return 0;
39 : : }
40 : :
41 : : numeric *
7593 42 : 6651 : PGTYPESnumeric_new(void)
43 : : {
44 : : numeric *var;
45 : :
7523 46 [ - + ]: 6651 : if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
7700 meskes@postgresql.or 47 :UBC 0 : return NULL;
48 : :
7559 bruce@momjian.us 49 [ - + ]:CBC 6651 : if (alloc_var(var, 0) < 0)
50 : : {
6507 meskes@postgresql.or 51 :UBC 0 : free(var);
7700 52 : 0 : return NULL;
53 : : }
54 : :
7700 meskes@postgresql.or 55 :CBC 6651 : return var;
56 : : }
57 : :
58 : : decimal *
6458 59 : 46 : PGTYPESdecimal_new(void)
60 : : {
61 : : decimal *var;
62 : :
63 [ - + ]: 46 : if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
6458 meskes@postgresql.or 64 :UBC 0 : return NULL;
65 : :
6458 meskes@postgresql.or 66 :CBC 46 : memset(var, 0, sizeof(decimal));
67 : :
68 : 46 : return var;
69 : : }
70 : :
71 : : /* ----------
72 : : * set_var_from_str()
73 : : *
74 : : * Parse a string and put the number into a variable
75 : : * ----------
76 : : */
77 : : static int
6718 bruce@momjian.us 78 : 85 : set_var_from_str(char *str, char **ptr, numeric *dest)
79 : : {
2433 peter_e@gmx.net 80 : 85 : bool have_dp = false;
7559 bruce@momjian.us 81 : 85 : int i = 0;
82 : :
7512 meskes@postgresql.or 83 : 85 : errno = 0;
7700 84 : 85 : *ptr = str;
85 [ + - ]: 85 : while (*(*ptr))
86 : : {
87 [ + - ]: 85 : if (!isspace((unsigned char) *(*ptr)))
88 : 85 : break;
7700 meskes@postgresql.or 89 :UBC 0 : (*ptr)++;
90 : : }
91 : :
5185 meskes@postgresql.or 92 [ + + ]:CBC 85 : if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
93 : : {
94 : 12 : *ptr += 3;
95 : 12 : dest->sign = NUMERIC_NAN;
96 : :
97 : : /* Should be nothing left but spaces */
98 [ - + ]: 12 : while (*(*ptr))
99 : : {
5185 meskes@postgresql.or 100 [ # # ]:UBC 0 : if (!isspace((unsigned char) *(*ptr)))
101 : : {
102 : 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
103 : 0 : return -1;
104 : : }
105 : 0 : (*ptr)++;
106 : : }
107 : :
5185 meskes@postgresql.or 108 :CBC 12 : return 0;
109 : : }
110 : :
7700 111 [ - + ]: 73 : if (alloc_var(dest, strlen((*ptr))) < 0)
7700 meskes@postgresql.or 112 :UBC 0 : return -1;
7700 meskes@postgresql.or 113 :CBC 73 : dest->weight = -1;
114 : 73 : dest->dscale = 0;
115 : 73 : dest->sign = NUMERIC_POS;
116 : :
117 [ + + + ]: 73 : switch (*(*ptr))
118 : : {
119 : 4 : case '+':
120 : 4 : dest->sign = NUMERIC_POS;
121 : 4 : (*ptr)++;
122 : 4 : break;
123 : :
124 : 9 : case '-':
125 : 9 : dest->sign = NUMERIC_NEG;
126 : 9 : (*ptr)++;
127 : 9 : break;
128 : : }
129 : :
130 [ + + ]: 73 : if (*(*ptr) == '.')
131 : : {
2433 peter_e@gmx.net 132 : 10 : have_dp = true;
7700 meskes@postgresql.or 133 : 10 : (*ptr)++;
134 : : }
135 : :
136 [ + + ]: 73 : if (!isdigit((unsigned char) *(*ptr)))
137 : : {
7559 bruce@momjian.us 138 : 2 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 meskes@postgresql.or 139 : 2 : return -1;
140 : : }
141 : :
142 [ + + ]: 459 : while (*(*ptr))
143 : : {
144 [ + + ]: 403 : if (isdigit((unsigned char) *(*ptr)))
145 : : {
146 : 342 : dest->digits[i++] = *(*ptr)++ - '0';
147 [ + + ]: 342 : if (!have_dp)
148 : 218 : dest->weight++;
149 : : else
150 : 124 : dest->dscale++;
151 : : }
152 [ + + ]: 61 : else if (*(*ptr) == '.')
153 : : {
154 [ - + ]: 46 : if (have_dp)
155 : : {
7686 meskes@postgresql.or 156 :UBC 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 157 : 0 : return -1;
158 : : }
2433 peter_e@gmx.net 159 :CBC 46 : have_dp = true;
7700 meskes@postgresql.or 160 : 46 : (*ptr)++;
161 : : }
162 : : else
163 : 15 : break;
164 : : }
165 : 71 : dest->ndigits = i;
166 : :
167 : : /* Handle exponent, if any */
168 [ + + + + ]: 71 : if (*(*ptr) == 'e' || *(*ptr) == 'E')
169 : : {
170 : : long exponent;
171 : : char *endptr;
172 : :
173 : 15 : (*ptr)++;
6900 bruce@momjian.us 174 : 15 : exponent = strtol(*ptr, &endptr, 10);
7700 meskes@postgresql.or 175 [ - + ]: 15 : if (endptr == (*ptr))
176 : : {
7686 meskes@postgresql.or 177 :UBC 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 178 : 0 : return -1;
179 : : }
7700 meskes@postgresql.or 180 :CBC 15 : (*ptr) = endptr;
2800 tgl@sss.pgh.pa.us 181 [ + - - + ]: 15 : if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
182 : : {
7686 meskes@postgresql.or 183 :UBC 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 184 : 0 : return -1;
185 : : }
7700 meskes@postgresql.or 186 :CBC 15 : dest->weight += (int) exponent;
187 : 15 : dest->dscale -= (int) exponent;
188 [ + + ]: 15 : if (dest->dscale < 0)
189 : 7 : dest->dscale = 0;
190 : : }
191 : :
192 : : /* Should be nothing left but spaces */
193 [ - + ]: 71 : while (*(*ptr))
194 : : {
7700 meskes@postgresql.or 195 [ # # ]:UBC 0 : if (!isspace((unsigned char) *(*ptr)))
196 : : {
7686 197 : 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 198 : 0 : return -1;
199 : : }
200 : 0 : (*ptr)++;
201 : : }
202 : :
203 : : /* Strip any leading zeroes */
7700 meskes@postgresql.or 204 [ + + + + ]:CBC 96 : while (dest->ndigits > 0 && *(dest->digits) == 0)
205 : : {
206 : 25 : (dest->digits)++;
207 : 25 : (dest->weight)--;
208 : 25 : (dest->ndigits)--;
209 : : }
210 [ + + ]: 71 : if (dest->ndigits == 0)
211 : 8 : dest->weight = 0;
212 : :
213 : 71 : dest->rscale = dest->dscale;
2432 peter_e@gmx.net 214 : 71 : return 0;
215 : : }
216 : :
217 : :
218 : : /* ----------
219 : : * get_str_from_var() -
220 : : *
221 : : * Convert a var to text representation (guts of numeric_out).
222 : : * CAUTION: var's contents may be modified by rounding!
223 : : * ----------
224 : : */
225 : : static char *
6718 bruce@momjian.us 226 : 1962 : get_str_from_var(numeric *var, int dscale)
227 : : {
228 : : char *str;
229 : : char *cp;
230 : : int i;
231 : : int d;
232 : :
5185 meskes@postgresql.or 233 [ + + ]: 1962 : if (var->sign == NUMERIC_NAN)
234 : : {
235 : 5 : str = (char *) pgtypes_alloc(4);
236 [ - + ]: 5 : if (str == NULL)
5185 meskes@postgresql.or 237 :UBC 0 : return NULL;
5185 meskes@postgresql.or 238 :CBC 5 : sprintf(str, "NaN");
239 : 5 : return str;
240 : : }
241 : :
242 : : /*
243 : : * Check if we must round up before printing the value and do so.
244 : : */
7700 245 : 1957 : i = dscale + var->weight + 1;
246 [ + + + + ]: 1957 : if (i >= 0 && var->ndigits > i)
247 : 299 : {
248 : 299 : int carry = (var->digits[i] > 4) ? 1 : 0;
249 : :
250 : 299 : var->ndigits = i;
251 : :
252 [ + + ]: 1473 : while (carry)
253 : : {
254 : 1174 : carry += var->digits[--i];
255 : 1174 : var->digits[i] = carry % 10;
256 : 1174 : carry /= 10;
257 : : }
258 : :
259 [ + + ]: 299 : if (i < 0)
260 : : {
261 : 20 : var->digits--;
262 : 20 : var->ndigits++;
263 : 20 : var->weight++;
264 : : }
265 : : }
266 : : else
267 : 1658 : var->ndigits = Max(0, Min(i, var->ndigits));
268 : :
269 : : /*
270 : : * Allocate space for the result
271 : : */
7559 bruce@momjian.us 272 [ - + ]: 1957 : if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
7700 meskes@postgresql.or 273 :UBC 0 : return NULL;
7700 meskes@postgresql.or 274 :CBC 1957 : cp = str;
275 : :
276 : : /*
277 : : * Output a dash for negative values
278 : : */
279 [ + + ]: 1957 : if (var->sign == NUMERIC_NEG)
280 : 648 : *cp++ = '-';
281 : :
282 : : /*
283 : : * Output all digits before the decimal point
284 : : */
285 : 1957 : i = Max(var->weight, 0);
286 : 1957 : d = 0;
287 : :
288 [ + + ]: 82639 : while (i >= 0)
289 : : {
290 [ + + + + ]: 80682 : if (i <= var->weight && d < var->ndigits)
291 : 35494 : *cp++ = var->digits[d++] + '0';
292 : : else
293 : 45188 : *cp++ = '0';
294 : 80682 : i--;
295 : : }
296 : :
297 : : /*
298 : : * If requested, output a decimal point and all the digits that follow it.
299 : : */
300 [ + + ]: 1957 : if (dscale > 0)
301 : : {
302 : 1785 : *cp++ = '.';
303 [ + + ]: 47208 : while (i >= -dscale)
304 : : {
305 [ + + + + ]: 45423 : if (i <= var->weight && d < var->ndigits)
306 : 7370 : *cp++ = var->digits[d++] + '0';
307 : : else
308 : 38053 : *cp++ = '0';
309 : 45423 : i--;
310 : : }
311 : : }
312 : :
313 : : /*
314 : : * terminate the string and return it
315 : : */
316 : 1957 : *cp = '\0';
317 : 1957 : return str;
318 : : }
319 : :
320 : : numeric *
7684 321 : 85 : PGTYPESnumeric_from_asc(char *str, char **endptr)
322 : : {
7523 323 : 85 : numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
324 : : int ret;
325 : :
326 : : char *realptr;
7559 bruce@momjian.us 327 [ + + ]: 85 : char **ptr = (endptr != NULL) ? endptr : &realptr;
328 : :
6402 329 [ - + ]: 85 : if (!value)
2432 peter_e@gmx.net 330 :UBC 0 : return NULL;
331 : :
7700 meskes@postgresql.or 332 :CBC 85 : ret = set_var_from_str(str, ptr, value);
333 [ + + ]: 85 : if (ret)
334 : : {
4989 335 : 2 : PGTYPESnumeric_free(value);
2432 peter_e@gmx.net 336 : 2 : return NULL;
337 : : }
338 : :
339 : 83 : return value;
340 : : }
341 : :
342 : : char *
6718 bruce@momjian.us 343 : 1934 : PGTYPESnumeric_to_asc(numeric *num, int dscale)
344 : : {
6402 345 : 1934 : numeric *numcopy = PGTYPESnumeric_new();
346 : : char *s;
347 : :
3871 meskes@postgresql.or 348 [ - + ]: 1934 : if (numcopy == NULL)
3871 meskes@postgresql.or 349 :UBC 0 : return NULL;
350 : :
6460 meskes@postgresql.or 351 [ - + ]:CBC 1934 : if (PGTYPESnumeric_copy(num, numcopy) < 0)
352 : : {
6458 meskes@postgresql.or 353 :UBC 0 : PGTYPESnumeric_free(numcopy);
6460 354 : 0 : return NULL;
355 : : }
356 : :
3871 meskes@postgresql.or 357 [ + + ]:CBC 1934 : if (dscale < 0)
358 : 56 : dscale = num->dscale;
359 : :
360 : : /* get_str_from_var may change its argument */
6460 361 : 1934 : s = get_str_from_var(numcopy, dscale);
362 : 1934 : PGTYPESnumeric_free(numcopy);
2432 peter_e@gmx.net 363 : 1934 : return s;
364 : : }
365 : :
366 : : /* ----------
367 : : * zero_var() -
368 : : *
369 : : * Set a variable to ZERO.
370 : : * Note: rscale and dscale are not touched.
371 : : * ----------
372 : : */
373 : : static void
6718 bruce@momjian.us 374 : 4988 : zero_var(numeric *var)
375 : : {
7700 meskes@postgresql.or 376 : 4988 : digitbuf_free(var->buf);
377 : 4988 : var->buf = NULL;
378 : 4988 : var->digits = NULL;
379 : 4988 : var->ndigits = 0;
380 : 4988 : var->weight = 0; /* by convention; doesn't really matter */
381 : 4988 : var->sign = NUMERIC_POS; /* anything but NAN... */
382 : 4988 : }
383 : :
384 : : void
6718 bruce@momjian.us 385 : 6716 : PGTYPESnumeric_free(numeric *var)
386 : : {
7700 meskes@postgresql.or 387 : 6716 : digitbuf_free(var->buf);
388 : 6716 : free(var);
389 : 6716 : }
390 : :
391 : : void
6458 392 : 46 : PGTYPESdecimal_free(decimal *var)
393 : : {
394 : 46 : free(var);
395 : 46 : }
396 : :
397 : : /* ----------
398 : : * cmp_abs() -
399 : : *
400 : : * Compare the absolute values of var1 and var2
401 : : * Returns: -1 for ABS(var1) < ABS(var2)
402 : : * 0 for ABS(var1) == ABS(var2)
403 : : * 1 for ABS(var1) > ABS(var2)
404 : : * ----------
405 : : */
406 : : static int
6718 bruce@momjian.us 407 : 23762 : cmp_abs(numeric *var1, numeric *var2)
408 : : {
7700 meskes@postgresql.or 409 : 23762 : int i1 = 0;
410 : 23762 : int i2 = 0;
411 : 23762 : int w1 = var1->weight;
412 : 23762 : int w2 = var2->weight;
413 : : int stat;
414 : :
415 [ + + + + ]: 23762 : while (w1 > w2 && i1 < var1->ndigits)
416 : : {
417 [ + - ]: 215 : if (var1->digits[i1++] != 0)
418 : 215 : return 1;
7700 meskes@postgresql.or 419 :UBC 0 : w1--;
420 : : }
7700 meskes@postgresql.or 421 [ + + + + ]:CBC 29961 : while (w2 > w1 && i2 < var2->ndigits)
422 : : {
423 [ + + ]: 8098 : if (var2->digits[i2++] != 0)
424 : 1684 : return -1;
425 : 6414 : w2--;
426 : : }
427 : :
428 [ + + ]: 21863 : if (w1 == w2)
429 : : {
430 [ + + + + ]: 39162 : while (i1 < var1->ndigits && i2 < var2->ndigits)
431 : : {
432 : 38328 : stat = var1->digits[i1++] - var2->digits[i2++];
433 [ + + ]: 38328 : if (stat)
434 : : {
435 [ + + ]: 20979 : if (stat > 0)
436 : 11298 : return 1;
437 : 9681 : return -1;
438 : : }
439 : : }
440 : : }
441 : :
442 [ + + ]: 966 : while (i1 < var1->ndigits)
443 : : {
444 [ + + ]: 425 : if (var1->digits[i1++] != 0)
445 : 343 : return 1;
446 : : }
447 [ + + ]: 763 : while (i2 < var2->ndigits)
448 : : {
449 [ + + ]: 561 : if (var2->digits[i2++] != 0)
450 : 339 : return -1;
451 : : }
452 : :
453 : 202 : return 0;
454 : : }
455 : :
456 : :
457 : : /* ----------
458 : : * add_abs() -
459 : : *
460 : : * Add the absolute values of two variables into result.
461 : : * result might point to one of the operands without danger.
462 : : * ----------
463 : : */
464 : : static int
6718 bruce@momjian.us 465 : 423 : add_abs(numeric *var1, numeric *var2, numeric *result)
466 : : {
467 : : NumericDigit *res_buf;
468 : : NumericDigit *res_digits;
469 : : int res_ndigits;
470 : : int res_weight;
471 : : int res_rscale;
472 : : int res_dscale;
473 : : int i,
474 : : i1,
475 : : i2;
7700 meskes@postgresql.or 476 : 423 : int carry = 0;
477 : :
478 : : /* copy these values into local vars for speed in inner loop */
479 : 423 : int var1ndigits = var1->ndigits;
480 : 423 : int var2ndigits = var2->ndigits;
481 : 423 : NumericDigit *var1digits = var1->digits;
482 : 423 : NumericDigit *var2digits = var2->digits;
483 : :
484 : 423 : res_weight = Max(var1->weight, var2->weight) + 1;
485 : 423 : res_rscale = Max(var1->rscale, var2->rscale);
486 : 423 : res_dscale = Max(var1->dscale, var2->dscale);
487 : 423 : res_ndigits = res_rscale + res_weight + 1;
488 [ - + ]: 423 : if (res_ndigits <= 0)
7700 meskes@postgresql.or 489 :UBC 0 : res_ndigits = 1;
490 : :
7700 meskes@postgresql.or 491 [ - + ]:CBC 423 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
7700 meskes@postgresql.or 492 :UBC 0 : return -1;
7700 meskes@postgresql.or 493 :CBC 423 : res_digits = res_buf;
494 : :
495 : 423 : i1 = res_rscale + var1->weight + 1;
496 : 423 : i2 = res_rscale + var2->weight + 1;
497 [ + + ]: 49465 : for (i = res_ndigits - 1; i >= 0; i--)
498 : : {
499 : 49042 : i1--;
500 : 49042 : i2--;
501 [ + + + + ]: 49042 : if (i1 >= 0 && i1 < var1ndigits)
502 : 2531 : carry += var1digits[i1];
503 [ + + + + ]: 49042 : if (i2 >= 0 && i2 < var2ndigits)
504 : 2530 : carry += var2digits[i2];
505 : :
506 [ + + ]: 49042 : if (carry >= 10)
507 : : {
508 : 216 : res_digits[i] = carry - 10;
509 : 216 : carry = 1;
510 : : }
511 : : else
512 : : {
513 : 48826 : res_digits[i] = carry;
514 : 48826 : carry = 0;
515 : : }
516 : : }
517 : :
518 [ + + + + ]: 2460 : while (res_ndigits > 0 && *res_digits == 0)
519 : : {
520 : 2037 : res_digits++;
521 : 2037 : res_weight--;
522 : 2037 : res_ndigits--;
523 : : }
524 [ + + + + ]: 3022 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
525 : 2599 : res_ndigits--;
526 : :
527 [ + + ]: 423 : if (res_ndigits == 0)
528 : 2 : res_weight = 0;
529 : :
530 : 423 : digitbuf_free(result->buf);
531 : 423 : result->ndigits = res_ndigits;
532 : 423 : result->buf = res_buf;
533 : 423 : result->digits = res_digits;
534 : 423 : result->weight = res_weight;
535 : 423 : result->rscale = res_rscale;
536 : 423 : result->dscale = res_dscale;
537 : :
538 : 423 : return 0;
539 : : }
540 : :
541 : :
542 : : /* ----------
543 : : * sub_abs() -
544 : : *
545 : : * Subtract the absolute value of var2 from the absolute value of var1
546 : : * and store in result. result might point to one of the operands
547 : : * without danger.
548 : : *
549 : : * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
550 : : * ----------
551 : : */
552 : : static int
6718 bruce@momjian.us 553 : 11981 : sub_abs(numeric *var1, numeric *var2, numeric *result)
554 : : {
555 : : NumericDigit *res_buf;
556 : : NumericDigit *res_digits;
557 : : int res_ndigits;
558 : : int res_weight;
559 : : int res_rscale;
560 : : int res_dscale;
561 : : int i,
562 : : i1,
563 : : i2;
7700 meskes@postgresql.or 564 : 11981 : int borrow = 0;
565 : :
566 : : /* copy these values into local vars for speed in inner loop */
567 : 11981 : int var1ndigits = var1->ndigits;
568 : 11981 : int var2ndigits = var2->ndigits;
569 : 11981 : NumericDigit *var1digits = var1->digits;
570 : 11981 : NumericDigit *var2digits = var2->digits;
571 : :
572 : 11981 : res_weight = var1->weight;
573 : 11981 : res_rscale = Max(var1->rscale, var2->rscale);
574 : 11981 : res_dscale = Max(var1->dscale, var2->dscale);
575 : 11981 : res_ndigits = res_rscale + res_weight + 1;
576 [ - + ]: 11981 : if (res_ndigits <= 0)
7700 meskes@postgresql.or 577 :UBC 0 : res_ndigits = 1;
578 : :
7700 meskes@postgresql.or 579 [ - + ]:CBC 11981 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
7700 meskes@postgresql.or 580 :UBC 0 : return -1;
7700 meskes@postgresql.or 581 :CBC 11981 : res_digits = res_buf;
582 : :
583 : 11981 : i1 = res_rscale + var1->weight + 1;
584 : 11981 : i2 = res_rscale + var2->weight + 1;
585 [ + + ]: 181995 : for (i = res_ndigits - 1; i >= 0; i--)
586 : : {
587 : 170014 : i1--;
588 : 170014 : i2--;
589 [ + - + + ]: 170014 : if (i1 >= 0 && i1 < var1ndigits)
590 : 102082 : borrow += var1digits[i1];
591 [ + + + + ]: 170014 : if (i2 >= 0 && i2 < var2ndigits)
592 : 101624 : borrow -= var2digits[i2];
593 : :
594 [ + + ]: 170014 : if (borrow < 0)
595 : : {
596 : 82839 : res_digits[i] = borrow + 10;
597 : 82839 : borrow = -1;
598 : : }
599 : : else
600 : : {
601 : 87175 : res_digits[i] = borrow;
602 : 87175 : borrow = 0;
603 : : }
604 : : }
605 : :
606 [ + - + + ]: 25346 : while (res_ndigits > 0 && *res_digits == 0)
607 : : {
608 : 13365 : res_digits++;
609 : 13365 : res_weight--;
610 : 13365 : res_ndigits--;
611 : : }
612 [ + - + + ]: 25929 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
613 : 13948 : res_ndigits--;
614 : :
615 [ - + ]: 11981 : if (res_ndigits == 0)
7700 meskes@postgresql.or 616 :UBC 0 : res_weight = 0;
617 : :
7700 meskes@postgresql.or 618 :CBC 11981 : digitbuf_free(result->buf);
619 : 11981 : result->ndigits = res_ndigits;
620 : 11981 : result->buf = res_buf;
621 : 11981 : result->digits = res_digits;
622 : 11981 : result->weight = res_weight;
623 : 11981 : result->rscale = res_rscale;
624 : 11981 : result->dscale = res_dscale;
625 : :
626 : 11981 : return 0;
627 : : }
628 : :
629 : : /* ----------
630 : : * add_var() -
631 : : *
632 : : * Full version of add functionality on variable level (handling signs).
633 : : * result might point to one of the operands too without danger.
634 : : * ----------
635 : : */
636 : : int
6718 bruce@momjian.us 637 : 423 : PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
638 : : {
639 : : /*
640 : : * Decide on the signs of the two variables what to do
641 : : */
7700 meskes@postgresql.or 642 [ + + ]: 423 : if (var1->sign == NUMERIC_POS)
643 : : {
644 [ + + ]: 307 : if (var2->sign == NUMERIC_POS)
645 : : {
646 : : /*
647 : : * Both are positive result = +(ABS(var1) + ABS(var2))
648 : : */
649 [ - + ]: 223 : if (add_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 650 :UBC 0 : return -1;
7700 meskes@postgresql.or 651 :CBC 223 : result->sign = NUMERIC_POS;
652 : : }
653 : : else
654 : : {
655 : : /*
656 : : * var1 is positive, var2 is negative Must compare absolute values
657 : : */
658 [ - + + - ]: 84 : switch (cmp_abs(var1, var2))
659 : : {
7700 meskes@postgresql.or 660 :UBC 0 : case 0:
661 : : /* ----------
662 : : * ABS(var1) == ABS(var2)
663 : : * result = ZERO
664 : : * ----------
665 : : */
666 : 0 : zero_var(result);
667 : 0 : result->rscale = Max(var1->rscale, var2->rscale);
668 : 0 : result->dscale = Max(var1->dscale, var2->dscale);
669 : 0 : break;
670 : :
7700 meskes@postgresql.or 671 :CBC 46 : case 1:
672 : : /* ----------
673 : : * ABS(var1) > ABS(var2)
674 : : * result = +(ABS(var1) - ABS(var2))
675 : : * ----------
676 : : */
677 [ - + ]: 46 : if (sub_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 678 :UBC 0 : return -1;
7700 meskes@postgresql.or 679 :CBC 46 : result->sign = NUMERIC_POS;
680 : 46 : break;
681 : :
682 : 38 : case -1:
683 : : /* ----------
684 : : * ABS(var1) < ABS(var2)
685 : : * result = -(ABS(var2) - ABS(var1))
686 : : * ----------
687 : : */
688 [ - + ]: 38 : if (sub_abs(var2, var1, result) != 0)
7700 meskes@postgresql.or 689 :UBC 0 : return -1;
7700 meskes@postgresql.or 690 :CBC 38 : result->sign = NUMERIC_NEG;
691 : 38 : break;
692 : : }
693 : : }
694 : : }
695 : : else
696 : : {
697 [ + + ]: 116 : if (var2->sign == NUMERIC_POS)
698 : : {
699 : : /* ----------
700 : : * var1 is negative, var2 is positive
701 : : * Must compare absolute values
702 : : * ----------
703 : : */
704 [ - + + - ]: 84 : switch (cmp_abs(var1, var2))
705 : : {
7700 meskes@postgresql.or 706 :UBC 0 : case 0:
707 : : /* ----------
708 : : * ABS(var1) == ABS(var2)
709 : : * result = ZERO
710 : : * ----------
711 : : */
712 : 0 : zero_var(result);
713 : 0 : result->rscale = Max(var1->rscale, var2->rscale);
714 : 0 : result->dscale = Max(var1->dscale, var2->dscale);
715 : 0 : break;
716 : :
7700 meskes@postgresql.or 717 :CBC 38 : case 1:
718 : : /* ----------
719 : : * ABS(var1) > ABS(var2)
720 : : * result = -(ABS(var1) - ABS(var2))
721 : : * ----------
722 : : */
723 [ - + ]: 38 : if (sub_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 724 :UBC 0 : return -1;
7700 meskes@postgresql.or 725 :CBC 38 : result->sign = NUMERIC_NEG;
726 : 38 : break;
727 : :
728 : 46 : case -1:
729 : : /* ----------
730 : : * ABS(var1) < ABS(var2)
731 : : * result = +(ABS(var2) - ABS(var1))
732 : : * ----------
733 : : */
734 [ - + ]: 46 : if (sub_abs(var2, var1, result) != 0)
7700 meskes@postgresql.or 735 :UBC 0 : return -1;
7700 meskes@postgresql.or 736 :CBC 46 : result->sign = NUMERIC_POS;
737 : 46 : break;
738 : : }
739 : : }
740 : : else
741 : : {
742 : : /* ----------
743 : : * Both are negative
744 : : * result = -(ABS(var1) + ABS(var2))
745 : : * ----------
746 : : */
747 [ - + ]: 32 : if (add_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 748 :UBC 0 : return -1;
7700 meskes@postgresql.or 749 :CBC 32 : result->sign = NUMERIC_NEG;
750 : : }
751 : : }
752 : :
753 : 423 : return 0;
754 : : }
755 : :
756 : :
757 : : /* ----------
758 : : * sub_var() -
759 : : *
760 : : * Full version of sub functionality on variable level (handling signs).
761 : : * result might point to one of the operands too without danger.
762 : : * ----------
763 : : */
764 : : int
6718 bruce@momjian.us 765 : 422 : PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
766 : : {
767 : : /*
768 : : * Decide on the signs of the two variables what to do
769 : : */
7700 meskes@postgresql.or 770 [ + + ]: 422 : if (var1->sign == NUMERIC_POS)
771 : : {
772 [ + + ]: 306 : if (var2->sign == NUMERIC_NEG)
773 : : {
774 : : /* ----------
775 : : * var1 is positive, var2 is negative
776 : : * result = +(ABS(var1) + ABS(var2))
777 : : * ----------
778 : : */
779 [ - + ]: 84 : if (add_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 780 :UBC 0 : return -1;
7700 meskes@postgresql.or 781 :CBC 84 : result->sign = NUMERIC_POS;
782 : : }
783 : : else
784 : : {
785 : : /* ----------
786 : : * Both are positive
787 : : * Must compare absolute values
788 : : * ----------
789 : : */
790 [ + + + - ]: 222 : switch (cmp_abs(var1, var2))
791 : : {
792 : 21 : case 0:
793 : : /* ----------
794 : : * ABS(var1) == ABS(var2)
795 : : * result = ZERO
796 : : * ----------
797 : : */
798 : 21 : zero_var(result);
799 : 21 : result->rscale = Max(var1->rscale, var2->rscale);
800 : 21 : result->dscale = Max(var1->dscale, var2->dscale);
801 : 21 : break;
802 : :
803 : 101 : case 1:
804 : : /* ----------
805 : : * ABS(var1) > ABS(var2)
806 : : * result = +(ABS(var1) - ABS(var2))
807 : : * ----------
808 : : */
809 [ - + ]: 101 : if (sub_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 810 :UBC 0 : return -1;
7700 meskes@postgresql.or 811 :CBC 101 : result->sign = NUMERIC_POS;
812 : 101 : break;
813 : :
814 : 100 : case -1:
815 : : /* ----------
816 : : * ABS(var1) < ABS(var2)
817 : : * result = -(ABS(var2) - ABS(var1))
818 : : * ----------
819 : : */
820 [ - + ]: 100 : if (sub_abs(var2, var1, result) != 0)
7700 meskes@postgresql.or 821 :UBC 0 : return -1;
7700 meskes@postgresql.or 822 :CBC 100 : result->sign = NUMERIC_NEG;
823 : 100 : break;
824 : : }
825 : : }
826 : : }
827 : : else
828 : : {
829 [ + + ]: 116 : if (var2->sign == NUMERIC_NEG)
830 : : {
831 : : /* ----------
832 : : * Both are negative
833 : : * Must compare absolute values
834 : : * ----------
835 : : */
836 [ + + + - ]: 32 : switch (cmp_abs(var1, var2))
837 : : {
838 : 8 : case 0:
839 : : /* ----------
840 : : * ABS(var1) == ABS(var2)
841 : : * result = ZERO
842 : : * ----------
843 : : */
844 : 8 : zero_var(result);
845 : 8 : result->rscale = Max(var1->rscale, var2->rscale);
846 : 8 : result->dscale = Max(var1->dscale, var2->dscale);
847 : 8 : break;
848 : :
849 : 12 : case 1:
850 : : /* ----------
851 : : * ABS(var1) > ABS(var2)
852 : : * result = -(ABS(var1) - ABS(var2))
853 : : * ----------
854 : : */
855 [ - + ]: 12 : if (sub_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 856 :UBC 0 : return -1;
7700 meskes@postgresql.or 857 :CBC 12 : result->sign = NUMERIC_NEG;
858 : 12 : break;
859 : :
860 : 12 : case -1:
861 : : /* ----------
862 : : * ABS(var1) < ABS(var2)
863 : : * result = +(ABS(var2) - ABS(var1))
864 : : * ----------
865 : : */
866 [ - + ]: 12 : if (sub_abs(var2, var1, result) != 0)
7700 meskes@postgresql.or 867 :UBC 0 : return -1;
7700 meskes@postgresql.or 868 :CBC 12 : result->sign = NUMERIC_POS;
869 : 12 : break;
870 : : }
871 : : }
872 : : else
873 : : {
874 : : /* ----------
875 : : * var1 is negative, var2 is positive
876 : : * result = -(ABS(var1) + ABS(var2))
877 : : * ----------
878 : : */
879 [ - + ]: 84 : if (add_abs(var1, var2, result) != 0)
7700 meskes@postgresql.or 880 :UBC 0 : return -1;
7700 meskes@postgresql.or 881 :CBC 84 : result->sign = NUMERIC_NEG;
882 : : }
883 : : }
884 : :
885 : 422 : return 0;
886 : : }
887 : :
888 : : /* ----------
889 : : * mul_var() -
890 : : *
891 : : * Multiplication on variable level. Product of var1 * var2 is stored
892 : : * in result. Accuracy of result is determined by global_rscale.
893 : : * ----------
894 : : */
895 : : int
6718 bruce@momjian.us 896 : 423 : PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result)
897 : : {
898 : : NumericDigit *res_buf;
899 : : NumericDigit *res_digits;
900 : : int res_ndigits;
901 : : int res_weight;
902 : : int res_sign;
903 : : int i,
904 : : ri,
905 : : i1,
906 : : i2;
7700 meskes@postgresql.or 907 : 423 : long sum = 0;
7559 bruce@momjian.us 908 : 423 : int global_rscale = var1->rscale + var2->rscale;
909 : :
7700 meskes@postgresql.or 910 : 423 : res_weight = var1->weight + var2->weight + 2;
911 : 423 : res_ndigits = var1->ndigits + var2->ndigits + 1;
912 [ + + ]: 423 : if (var1->sign == var2->sign)
913 : 255 : res_sign = NUMERIC_POS;
914 : : else
915 : 168 : res_sign = NUMERIC_NEG;
916 : :
917 [ - + ]: 423 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
7559 bruce@momjian.us 918 :UBC 0 : return -1;
7700 meskes@postgresql.or 919 :CBC 423 : res_digits = res_buf;
920 : 423 : memset(res_digits, 0, res_ndigits);
921 : :
922 : 423 : ri = res_ndigits;
923 [ + + ]: 2961 : for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
924 : : {
925 : 2538 : sum = 0;
926 : 2538 : i = --ri;
927 : :
928 [ + + ]: 18107 : for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
929 : : {
930 : 15569 : sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
931 : 15569 : res_digits[i--] = sum % 10;
932 : 15569 : sum /= 10;
933 : : }
934 : 2538 : res_digits[i] = sum;
935 : : }
936 : :
937 : 423 : i = res_weight + global_rscale + 2;
938 [ + - - + ]: 423 : if (i >= 0 && i < res_ndigits)
939 : : {
7700 meskes@postgresql.or 940 :UBC 0 : sum = (res_digits[i] > 4) ? 1 : 0;
941 : 0 : res_ndigits = i;
942 : 0 : i--;
943 [ # # ]: 0 : while (sum)
944 : : {
945 : 0 : sum += res_digits[i];
946 : 0 : res_digits[i--] = sum % 10;
947 : 0 : sum /= 10;
948 : : }
949 : : }
950 : :
7700 meskes@postgresql.or 951 [ + + + + ]:CBC 1370 : while (res_ndigits > 0 && *res_digits == 0)
952 : : {
953 : 947 : res_digits++;
954 : 947 : res_weight--;
955 : 947 : res_ndigits--;
956 : : }
957 [ + + + + ]: 429 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
958 : 6 : res_ndigits--;
959 : :
960 [ + + ]: 423 : if (res_ndigits == 0)
961 : : {
962 : 56 : res_sign = NUMERIC_POS;
963 : 56 : res_weight = 0;
964 : : }
965 : :
966 : 423 : digitbuf_free(result->buf);
967 : 423 : result->buf = res_buf;
968 : 423 : result->digits = res_digits;
969 : 423 : result->ndigits = res_ndigits;
970 : 423 : result->weight = res_weight;
971 : 423 : result->rscale = global_rscale;
972 : 423 : result->sign = res_sign;
973 : 423 : result->dscale = var1->dscale + var2->dscale;
974 : :
975 : 423 : return 0;
976 : : }
977 : :
978 : : /*
979 : : * Default scale selection for division
980 : : *
981 : : * Returns the appropriate display scale for the division result,
982 : : * and sets global_rscale to the result scale to use during div_var.
983 : : *
984 : : * Note that this must be called before div_var.
985 : : */
986 : : static int
6718 bruce@momjian.us 987 : 422 : select_div_scale(numeric *var1, numeric *var2, int *rscale)
988 : : {
989 : : int weight1,
990 : : weight2,
991 : : qweight,
992 : : i;
993 : : NumericDigit firstdigit1,
994 : : firstdigit2;
995 : : int res_dscale;
996 : :
997 : : /*
998 : : * The result scale of a division isn't specified in any SQL standard. For
999 : : * PostgreSQL we select a display scale that will give at least
1000 : : * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
1001 : : * result no less accurate than float8; but use a scale not less than
1002 : : * either input's display scale.
1003 : : */
1004 : :
1005 : : /* Get the actual (normalized) weight and first digit of each input */
1006 : :
7700 meskes@postgresql.or 1007 : 422 : weight1 = 0; /* values to use if var1 is zero */
1008 : 422 : firstdigit1 = 0;
1009 [ + + ]: 422 : for (i = 0; i < var1->ndigits; i++)
1010 : : {
1011 : 393 : firstdigit1 = var1->digits[i];
1012 [ + - ]: 393 : if (firstdigit1 != 0)
1013 : : {
1014 : 393 : weight1 = var1->weight - i;
1015 : 393 : break;
1016 : : }
1017 : : }
1018 : :
1019 : 422 : weight2 = 0; /* values to use if var2 is zero */
1020 : 422 : firstdigit2 = 0;
1021 [ + + ]: 422 : for (i = 0; i < var2->ndigits; i++)
1022 : : {
1023 : 393 : firstdigit2 = var2->digits[i];
1024 [ + - ]: 393 : if (firstdigit2 != 0)
1025 : : {
1026 : 393 : weight2 = var2->weight - i;
1027 : 393 : break;
1028 : : }
1029 : : }
1030 : :
1031 : : /*
1032 : : * Estimate weight of quotient. If the two first digits are equal, we
1033 : : * can't be sure, but assume that var1 is less than var2.
1034 : : */
1035 : 422 : qweight = weight1 - weight2;
1036 [ + + ]: 422 : if (firstdigit1 <= firstdigit2)
1037 : 254 : qweight--;
1038 : :
1039 : : /* Select display scale */
1040 : 422 : res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1041 : 422 : res_dscale = Max(res_dscale, var1->dscale);
1042 : 422 : res_dscale = Max(res_dscale, var2->dscale);
1043 : 422 : res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1044 : 422 : res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1045 : :
1046 : : /* Select result scale */
5337 1047 : 422 : *rscale = res_dscale + 4;
1048 : :
7700 1049 : 422 : return res_dscale;
1050 : : }
1051 : :
1052 : : int
6718 bruce@momjian.us 1053 : 422 : PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result)
1054 : : {
1055 : : NumericDigit *res_digits;
1056 : : int res_ndigits;
1057 : : int res_sign;
1058 : : int res_weight;
1059 : : numeric dividend;
1060 : : numeric divisor[10];
1061 : : int ndigits_tmp;
1062 : : int weight_tmp;
1063 : : int rscale_tmp;
1064 : : int ri;
1065 : : long guess;
1066 : : long first_have;
1067 : : long first_div;
1068 : : int first_nextdigit;
7700 meskes@postgresql.or 1069 : 422 : int stat = 0;
1070 : : int rscale;
7559 bruce@momjian.us 1071 : 422 : int res_dscale = select_div_scale(var1, var2, &rscale);
6862 neilc@samurai.com 1072 : 422 : int err = -1;
1073 : : NumericDigit *tmp_buf;
1074 : :
1075 : : /*
1076 : : * First of all division by zero check
1077 : : */
7700 meskes@postgresql.or 1078 : 422 : ndigits_tmp = var2->ndigits + 1;
1079 [ + + ]: 422 : if (ndigits_tmp == 1)
1080 : : {
7559 bruce@momjian.us 1081 : 29 : errno = PGTYPES_NUM_DIVIDE_ZERO;
7700 meskes@postgresql.or 1082 : 29 : return -1;
1083 : : }
1084 : :
1085 : : /*
1086 : : * Determine the result sign, weight and number of digits to calculate
1087 : : */
1088 [ + + ]: 393 : if (var1->sign == var2->sign)
1089 : 233 : res_sign = NUMERIC_POS;
1090 : : else
1091 : 160 : res_sign = NUMERIC_NEG;
1092 : 393 : res_weight = var1->weight - var2->weight + 1;
1093 : 393 : res_ndigits = rscale + res_weight;
1094 [ - + ]: 393 : if (res_ndigits <= 0)
7700 meskes@postgresql.or 1095 :UBC 0 : res_ndigits = 1;
1096 : :
1097 : : /*
1098 : : * Now result zero check
1099 : : */
7700 meskes@postgresql.or 1100 [ + + ]:CBC 393 : if (var1->ndigits == 0)
1101 : : {
1102 : 27 : zero_var(result);
1103 : 27 : result->rscale = rscale;
1104 : 27 : return 0;
1105 : : }
1106 : :
1107 : : /*
1108 : : * Initialize local variables
1109 : : */
1110 : 366 : init_var(÷nd);
599 drowley@postgresql.o 1111 [ + + ]: 3660 : for (int i = 1; i < 10; i++)
7700 meskes@postgresql.or 1112 : 3294 : init_var(&divisor[i]);
1113 : :
1114 : : /*
1115 : : * Make a copy of the divisor which has one leading zero digit
1116 : : */
1117 : 366 : divisor[1].ndigits = ndigits_tmp;
1118 : 366 : divisor[1].rscale = var2->ndigits;
1119 : 366 : divisor[1].sign = NUMERIC_POS;
1120 : 366 : divisor[1].buf = digitbuf_alloc(ndigits_tmp);
6862 neilc@samurai.com 1121 [ - + ]: 366 : if (divisor[1].buf == NULL)
6862 neilc@samurai.com 1122 :UBC 0 : goto done;
7700 meskes@postgresql.or 1123 :CBC 366 : divisor[1].digits = divisor[1].buf;
1124 : 366 : divisor[1].digits[0] = 0;
1125 : 366 : memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1126 : :
1127 : : /*
1128 : : * Make a copy of the dividend
1129 : : */
1130 : 366 : dividend.ndigits = var1->ndigits;
1131 : 366 : dividend.weight = 0;
1132 : 366 : dividend.rscale = var1->ndigits;
1133 : 366 : dividend.sign = NUMERIC_POS;
1134 : 366 : dividend.buf = digitbuf_alloc(var1->ndigits);
6862 neilc@samurai.com 1135 [ - + ]: 366 : if (dividend.buf == NULL)
6862 neilc@samurai.com 1136 :UBC 0 : goto done;
7700 meskes@postgresql.or 1137 :CBC 366 : dividend.digits = dividend.buf;
1138 : 366 : memcpy(dividend.digits, var1->digits, var1->ndigits);
1139 : :
1140 : : /*
1141 : : * Setup the result. Do the allocation in a temporary buffer first, so we
1142 : : * don't free result->buf unless we have successfully allocated a buffer
1143 : : * to replace it with.
1144 : : */
6862 neilc@samurai.com 1145 : 366 : tmp_buf = digitbuf_alloc(res_ndigits + 2);
1146 [ - + ]: 366 : if (tmp_buf == NULL)
6862 neilc@samurai.com 1147 :UBC 0 : goto done;
7700 meskes@postgresql.or 1148 :CBC 366 : digitbuf_free(result->buf);
6862 neilc@samurai.com 1149 : 366 : result->buf = tmp_buf;
7700 meskes@postgresql.or 1150 : 366 : res_digits = result->buf;
1151 : 366 : result->digits = res_digits;
1152 : 366 : result->ndigits = res_ndigits;
1153 : 366 : result->weight = res_weight;
1154 : 366 : result->rscale = rscale;
1155 : 366 : result->sign = res_sign;
1156 : 366 : res_digits[0] = 0;
1157 : :
1158 : 366 : first_div = divisor[1].digits[1] * 10;
1159 [ + + ]: 366 : if (ndigits_tmp > 2)
1160 : 258 : first_div += divisor[1].digits[2];
1161 : :
1162 : 366 : first_have = 0;
1163 : 366 : first_nextdigit = 0;
1164 : :
1165 : 366 : weight_tmp = 1;
1166 : 366 : rscale_tmp = divisor[1].rscale;
1167 : :
1168 [ + + ]: 13790 : for (ri = 0; ri <= res_ndigits; ri++)
1169 : : {
1170 : 13557 : first_have = first_have * 10;
1171 [ + + + + ]: 13557 : if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1172 : 12583 : first_have += dividend.digits[first_nextdigit];
1173 : 13557 : first_nextdigit++;
1174 : :
1175 : 13557 : guess = (first_have * 10) / first_div + 1;
1176 [ + + ]: 13557 : if (guess > 9)
1177 : 1473 : guess = 9;
1178 : :
1179 [ + + ]: 25006 : while (guess > 0)
1180 : : {
1181 [ + + ]: 23170 : if (divisor[guess].buf == NULL)
1182 : : {
1183 : : int i;
1184 : 2277 : long sum = 0;
1185 : :
7523 1186 : 2277 : memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
7700 1187 : 2277 : divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
6862 neilc@samurai.com 1188 [ - + ]: 2277 : if (divisor[guess].buf == NULL)
6862 neilc@samurai.com 1189 :UBC 0 : goto done;
7700 meskes@postgresql.or 1190 :CBC 2277 : divisor[guess].digits = divisor[guess].buf;
1191 [ + + ]: 20515 : for (i = divisor[1].ndigits - 1; i >= 0; i--)
1192 : : {
1193 : 18238 : sum += divisor[1].digits[i] * guess;
1194 : 18238 : divisor[guess].digits[i] = sum % 10;
1195 : 18238 : sum /= 10;
1196 : : }
1197 : : }
1198 : :
1199 : 23170 : divisor[guess].weight = weight_tmp;
1200 : 23170 : divisor[guess].rscale = rscale_tmp;
1201 : :
1202 : 23170 : stat = cmp_abs(÷nd, &divisor[guess]);
1203 [ + + ]: 23170 : if (stat >= 0)
1204 : 11721 : break;
1205 : :
1206 : 11449 : guess--;
1207 : : }
1208 : :
1209 : 13557 : res_digits[ri + 1] = guess;
1210 [ + + ]: 13557 : if (stat == 0)
1211 : : {
1212 : 133 : ri++;
1213 : 133 : break;
1214 : : }
1215 : :
1216 : 13424 : weight_tmp--;
1217 : 13424 : rscale_tmp++;
1218 : :
1219 [ + + ]: 13424 : if (guess == 0)
1220 : 1836 : continue;
1221 : :
6862 neilc@samurai.com 1222 [ - + ]: 11588 : if (sub_abs(÷nd, &divisor[guess], ÷nd) != 0)
6862 neilc@samurai.com 1223 :UBC 0 : goto done;
1224 : :
7700 meskes@postgresql.or 1225 :CBC 11588 : first_nextdigit = dividend.weight - weight_tmp;
1226 : 11588 : first_have = 0;
1227 [ + + + - ]: 11588 : if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1228 : 7960 : first_have = dividend.digits[first_nextdigit];
1229 : 11588 : first_nextdigit++;
1230 : : }
1231 : :
1232 : 366 : result->ndigits = ri + 1;
1233 [ + + ]: 366 : if (ri == res_ndigits + 1)
1234 : : {
1235 : 233 : int carry = (res_digits[ri] > 4) ? 1 : 0;
1236 : :
1237 : 233 : result->ndigits = ri;
1238 : 233 : res_digits[ri] = 0;
1239 : :
1240 [ + + + - ]: 386 : while (carry && ri > 0)
1241 : : {
1242 : 153 : carry += res_digits[--ri];
1243 : 153 : res_digits[ri] = carry % 10;
1244 : 153 : carry /= 10;
1245 : : }
1246 : : }
1247 : :
1248 [ + - + + ]: 890 : while (result->ndigits > 0 && *(result->digits) == 0)
1249 : : {
1250 : 524 : (result->digits)++;
1251 : 524 : (result->weight)--;
1252 : 524 : (result->ndigits)--;
1253 : : }
1254 [ + - + + ]: 444 : while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1255 : 78 : (result->ndigits)--;
1256 [ - + ]: 366 : if (result->ndigits == 0)
7700 meskes@postgresql.or 1257 :UBC 0 : result->sign = NUMERIC_POS;
1258 : :
6862 neilc@samurai.com 1259 :CBC 366 : result->dscale = res_dscale;
6756 bruce@momjian.us 1260 : 366 : err = 0; /* if we've made it this far, return success */
1261 : :
6862 neilc@samurai.com 1262 : 366 : done:
1263 : :
1264 : : /*
1265 : : * Tidy up
1266 : : */
1267 [ + - ]: 366 : if (dividend.buf != NULL)
1268 : 366 : digitbuf_free(dividend.buf);
1269 : :
599 drowley@postgresql.o 1270 [ + + ]: 3660 : for (int i = 1; i < 10; i++)
1271 : : {
6862 neilc@samurai.com 1272 [ + + ]: 3294 : if (divisor[i].buf != NULL)
1273 : 2643 : digitbuf_free(divisor[i].buf);
1274 : : }
1275 : :
1276 : 366 : return err;
1277 : : }
1278 : :
1279 : :
1280 : : int
6718 bruce@momjian.us 1281 : 283 : PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
1282 : : {
1283 : : /* use cmp_abs function to calculate the result */
1284 : :
1285 : : /* both are positive: normal comparison with cmp_abs */
7559 1286 [ + + + + ]: 283 : if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
7700 meskes@postgresql.or 1287 : 138 : return cmp_abs(var1, var2);
1288 : :
1289 : : /* both are negative: return the inverse of the normal comparison */
7559 bruce@momjian.us 1290 [ + + + + ]: 145 : if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1291 : : {
1292 : : /*
1293 : : * instead of inverting the result, we invert the parameter ordering
1294 : : */
7700 meskes@postgresql.or 1295 : 32 : return cmp_abs(var2, var1);
1296 : : }
1297 : :
1298 : : /* one is positive, one is negative: trivial */
7559 bruce@momjian.us 1299 [ + + + + ]: 113 : if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
7700 meskes@postgresql.or 1300 : 40 : return 1;
7559 bruce@momjian.us 1301 [ + + + + ]: 73 : if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
7700 meskes@postgresql.or 1302 : 44 : return -1;
1303 : :
7686 1304 : 29 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 1305 : 29 : return INT_MAX;
1306 : : }
1307 : :
1308 : : int
6718 bruce@momjian.us 1309 : 36 : PGTYPESnumeric_from_int(signed int int_val, numeric *var)
1310 : : {
1311 : : /* implicit conversion */
7700 meskes@postgresql.or 1312 : 36 : signed long int long_int = int_val;
1313 : :
7684 1314 : 36 : return PGTYPESnumeric_from_long(long_int, var);
1315 : : }
1316 : :
1317 : : int
6718 bruce@momjian.us 1318 : 58 : PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
1319 : : {
1320 : : /* calculate the size of the long int number */
1321 : : /* a number n needs log_10 n digits */
1322 : :
1323 : : /*
1324 : : * however we multiply by 10 each time and compare instead of calculating
1325 : : * the logarithm
1326 : : */
1327 : :
7559 1328 : 58 : int size = 0;
1329 : : int i;
7700 meskes@postgresql.or 1330 : 58 : signed long int abs_long_val = long_val;
1331 : : signed long int extract;
1332 : : signed long int reach_limit;
1333 : :
7559 bruce@momjian.us 1334 [ + + ]: 58 : if (abs_long_val < 0)
1335 : : {
7700 meskes@postgresql.or 1336 : 12 : abs_long_val *= -1;
1337 : 12 : var->sign = NUMERIC_NEG;
1338 : : }
1339 : : else
7559 bruce@momjian.us 1340 : 46 : var->sign = NUMERIC_POS;
1341 : :
7700 meskes@postgresql.or 1342 : 58 : reach_limit = 1;
1343 : : do
1344 : : {
1345 : 82 : size++;
1346 : 82 : reach_limit *= 10;
6900 bruce@momjian.us 1347 [ + + + - ]: 82 : } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
1348 : :
7168 1349 [ - + ]: 58 : if (reach_limit > LONG_MAX / 10)
1350 : : {
1351 : : /* add the first digit and a .0 */
7495 meskes@postgresql.or 1352 :UBC 0 : size += 2;
1353 : : }
1354 : : else
1355 : : {
1356 : : /* always add a .0 */
7495 meskes@postgresql.or 1357 :CBC 58 : size++;
1358 : 58 : reach_limit /= 10;
1359 : : }
1360 : :
7559 bruce@momjian.us 1361 [ - + ]: 58 : if (alloc_var(var, size) < 0)
7700 meskes@postgresql.or 1362 :UBC 0 : return -1;
1363 : :
7700 meskes@postgresql.or 1364 :CBC 58 : var->rscale = 1;
1365 : 58 : var->dscale = 1;
1366 : 58 : var->weight = size - 2;
1367 : :
1368 : 58 : i = 0;
1369 : : do
1370 : : {
1371 : 74 : extract = abs_long_val - (abs_long_val % reach_limit);
1372 : 74 : var->digits[i] = extract / reach_limit;
1373 : 74 : abs_long_val -= extract;
1374 : 74 : i++;
7495 1375 : 74 : reach_limit /= 10;
1376 : :
1377 : : /*
1378 : : * we can abandon if abs_long_val reaches 0, because the memory is
1379 : : * initialized properly and filled with '0', so converting 10000 in
1380 : : * only one step is no problem
1381 : : */
7700 1382 [ + + ]: 74 : } while (abs_long_val > 0);
1383 : :
1384 : 58 : return 0;
1385 : : }
1386 : :
1387 : : int
6718 bruce@momjian.us 1388 : 2010 : PGTYPESnumeric_copy(numeric *src, numeric *dst)
1389 : : {
1390 : : int i;
1391 : :
7168 1392 [ - + ]: 2010 : if (dst == NULL)
7168 bruce@momjian.us 1393 :UBC 0 : return -1;
7700 meskes@postgresql.or 1394 :CBC 2010 : zero_var(dst);
1395 : :
1396 : 2010 : dst->weight = src->weight;
1397 : 2010 : dst->rscale = src->rscale;
1398 : 2010 : dst->dscale = src->dscale;
1399 : 2010 : dst->sign = src->sign;
1400 : :
1401 [ - + ]: 2010 : if (alloc_var(dst, src->ndigits) != 0)
7700 meskes@postgresql.or 1402 :UBC 0 : return -1;
1403 : :
7559 bruce@momjian.us 1404 [ + + ]:CBC 67378 : for (i = 0; i < src->ndigits; i++)
7700 meskes@postgresql.or 1405 : 65368 : dst->digits[i] = src->digits[i];
1406 : :
1407 : 2010 : return 0;
1408 : : }
1409 : :
1410 : : int
6718 bruce@momjian.us 1411 :UBC 0 : PGTYPESnumeric_from_double(double d, numeric *dst)
1412 : : {
1413 : : char buffer[DBL_DIG + 100];
1414 : : numeric *tmp;
1415 : : int i;
1416 : :
3057 tgl@sss.pgh.pa.us 1417 [ # # ]: 0 : if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
7700 meskes@postgresql.or 1418 : 0 : return -1;
1419 : :
7684 1420 [ # # ]: 0 : if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
7700 1421 : 0 : return -1;
6458 1422 : 0 : i = PGTYPESnumeric_copy(tmp, dst);
7700 1423 : 0 : PGTYPESnumeric_free(tmp);
6458 1424 [ # # ]: 0 : if (i != 0)
1425 : 0 : return -1;
1426 : :
6460 1427 : 0 : errno = 0;
7700 1428 : 0 : return 0;
1429 : : }
1430 : :
1431 : : static int
6458 meskes@postgresql.or 1432 :CBC 28 : numericvar_to_double(numeric *var, double *dp)
1433 : : {
1434 : : char *tmp;
1435 : : double val;
1436 : : char *endptr;
6402 bruce@momjian.us 1437 : 28 : numeric *varcopy = PGTYPESnumeric_new();
1438 : :
3871 meskes@postgresql.or 1439 [ - + ]: 28 : if (varcopy == NULL)
3871 meskes@postgresql.or 1440 :UBC 0 : return -1;
1441 : :
6460 meskes@postgresql.or 1442 [ - + ]:CBC 28 : if (PGTYPESnumeric_copy(var, varcopy) < 0)
1443 : : {
6458 meskes@postgresql.or 1444 :UBC 0 : PGTYPESnumeric_free(varcopy);
7700 1445 : 0 : return -1;
1446 : : }
1447 : :
6458 meskes@postgresql.or 1448 :CBC 28 : tmp = get_str_from_var(varcopy, varcopy->dscale);
6460 1449 : 28 : PGTYPESnumeric_free(varcopy);
1450 : :
6458 1451 [ - + ]: 28 : if (tmp == NULL)
6458 meskes@postgresql.or 1452 :UBC 0 : return -1;
1453 : :
1454 : : /*
1455 : : * strtod does not reset errno to 0 in case of success.
1456 : : */
6458 meskes@postgresql.or 1457 :CBC 28 : errno = 0;
7700 1458 : 28 : val = strtod(tmp, &endptr);
6460 1459 [ + + ]: 28 : if (errno == ERANGE)
1460 : : {
1461 : 2 : free(tmp);
6452 1462 [ - + ]: 2 : if (val == 0)
6452 meskes@postgresql.or 1463 :UBC 0 : errno = PGTYPES_NUM_UNDERFLOW;
1464 : : else
6452 meskes@postgresql.or 1465 :CBC 2 : errno = PGTYPES_NUM_OVERFLOW;
6460 1466 : 2 : return -1;
1467 : : }
1468 : :
1469 : : /* can't free tmp yet, endptr points still into it */
7700 1470 [ - + ]: 26 : if (*endptr != '\0')
1471 : : {
1472 : : /* shouldn't happen ... */
7700 meskes@postgresql.or 1473 :UBC 0 : free(tmp);
7686 1474 : 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
7700 1475 : 0 : return -1;
1476 : : }
7700 meskes@postgresql.or 1477 :CBC 26 : free(tmp);
6460 1478 : 26 : *dp = val;
7700 1479 : 26 : return 0;
1480 : : }
1481 : :
1482 : : int
6718 bruce@momjian.us 1483 : 28 : PGTYPESnumeric_to_double(numeric *nv, double *dp)
1484 : : {
1485 : : double tmp;
1486 : :
5337 meskes@postgresql.or 1487 [ + + ]: 28 : if (numericvar_to_double(nv, &tmp) != 0)
7700 1488 : 2 : return -1;
1489 : 26 : *dp = tmp;
1490 : 26 : return 0;
1491 : : }
1492 : :
1493 : : int
6718 bruce@momjian.us 1494 : 33 : PGTYPESnumeric_to_int(numeric *nv, int *ip)
1495 : : {
1496 : : long l;
1497 : : int i;
1498 : :
7684 meskes@postgresql.or 1499 [ + + ]: 33 : if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
7700 1500 : 7 : return i;
1501 : :
1502 : : /* silence compilers that might complain about useless tests */
1503 : : #if SIZEOF_LONG > SIZEOF_INT
1504 : :
989 john.naylor@postgres 1505 [ + - - + ]: 26 : if (l < INT_MIN || l > INT_MAX)
1506 : : {
7686 meskes@postgresql.or 1507 :UBC 0 : errno = PGTYPES_NUM_OVERFLOW;
7700 1508 : 0 : return -1;
1509 : : }
1510 : :
1511 : : #endif
1512 : :
7700 meskes@postgresql.or 1513 :CBC 26 : *ip = (int) l;
1514 : 26 : return 0;
1515 : : }
1516 : :
1517 : : int
6718 bruce@momjian.us 1518 : 64 : PGTYPESnumeric_to_long(numeric *nv, long *lp)
1519 : : {
6402 1520 : 64 : char *s = PGTYPESnumeric_to_asc(nv, 0);
1521 : : char *endptr;
1522 : :
6460 meskes@postgresql.or 1523 [ - + ]: 64 : if (s == NULL)
6460 meskes@postgresql.or 1524 :UBC 0 : return -1;
1525 : :
6460 meskes@postgresql.or 1526 :CBC 64 : errno = 0;
1527 : 64 : *lp = strtol(s, &endptr, 10);
1528 [ - + ]: 64 : if (endptr == s)
1529 : : {
1530 : : /* this should not happen actually */
4989 meskes@postgresql.or 1531 :UBC 0 : free(s);
6460 1532 : 0 : return -1;
1533 : : }
4989 meskes@postgresql.or 1534 :CBC 64 : free(s);
6460 1535 [ + + ]: 64 : if (errno == ERANGE)
1536 : : {
6452 1537 [ - + ]: 14 : if (*lp == LONG_MIN)
6452 meskes@postgresql.or 1538 :UBC 0 : errno = PGTYPES_NUM_UNDERFLOW;
1539 : : else
6452 meskes@postgresql.or 1540 :CBC 14 : errno = PGTYPES_NUM_OVERFLOW;
7700 1541 : 14 : return -1;
1542 : : }
1543 : 50 : return 0;
1544 : : }
1545 : :
1546 : : int
6718 bruce@momjian.us 1547 : 834 : PGTYPESnumeric_to_decimal(numeric *src, decimal *dst)
1548 : : {
1549 : : int i;
1550 : :
7559 1551 [ + + ]: 834 : if (src->ndigits > DECSIZE)
1552 : : {
7593 meskes@postgresql.or 1553 : 162 : errno = PGTYPES_NUM_OVERFLOW;
1554 : 162 : return -1;
1555 : : }
1556 : :
1557 : 672 : dst->weight = src->weight;
1558 : 672 : dst->rscale = src->rscale;
1559 : 672 : dst->dscale = src->dscale;
1560 : 672 : dst->sign = src->sign;
1561 : 672 : dst->ndigits = src->ndigits;
1562 : :
7559 bruce@momjian.us 1563 [ + + ]: 6806 : for (i = 0; i < src->ndigits; i++)
7593 meskes@postgresql.or 1564 : 6134 : dst->digits[i] = src->digits[i];
1565 : :
1566 : 672 : return 0;
1567 : : }
1568 : :
1569 : : int
6718 bruce@momjian.us 1570 : 2922 : PGTYPESnumeric_from_decimal(decimal *src, numeric *dst)
1571 : : {
1572 : : int i;
1573 : :
7593 meskes@postgresql.or 1574 : 2922 : zero_var(dst);
1575 : :
1576 : 2922 : dst->weight = src->weight;
1577 : 2922 : dst->rscale = src->rscale;
1578 : 2922 : dst->dscale = src->dscale;
1579 : 2922 : dst->sign = src->sign;
1580 : :
1581 [ - + ]: 2922 : if (alloc_var(dst, src->ndigits) != 0)
7593 meskes@postgresql.or 1582 :UBC 0 : return -1;
1583 : :
7559 bruce@momjian.us 1584 [ + + ]:CBC 20907 : for (i = 0; i < src->ndigits; i++)
7593 meskes@postgresql.or 1585 : 17985 : dst->digits[i] = src->digits[i];
1586 : :
1587 : 2922 : return 0;
1588 : : }
|