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
29 46856 : alloc_var(numeric *var, int ndigits)
30 : {
31 46856 : digitbuf_free(var->buf);
32 46856 : var->buf = digitbuf_alloc(ndigits + 1);
33 46856 : if (var->buf == NULL)
34 0 : return -1;
35 46856 : var->buf[0] = 0;
36 46856 : var->digits = var->buf + 1;
37 46856 : var->ndigits = ndigits;
38 46856 : return 0;
39 : }
40 :
41 : numeric *
42 26604 : PGTYPESnumeric_new(void)
43 : {
44 : numeric *var;
45 :
46 26604 : if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
47 0 : return NULL;
48 :
49 26604 : if (alloc_var(var, 0) < 0)
50 : {
51 0 : free(var);
52 0 : return NULL;
53 : }
54 :
55 26604 : return var;
56 : }
57 :
58 : decimal *
59 184 : PGTYPESdecimal_new(void)
60 : {
61 : decimal *var;
62 :
63 184 : if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
64 0 : return NULL;
65 :
66 184 : memset(var, 0, sizeof(decimal));
67 :
68 184 : 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
78 340 : set_var_from_str(char *str, char **ptr, numeric *dest)
79 : {
80 340 : bool have_dp = false;
81 340 : int i = 0;
82 :
83 340 : errno = 0;
84 340 : *ptr = str;
85 340 : while (*(*ptr))
86 : {
87 340 : if (!isspace((unsigned char) *(*ptr)))
88 340 : break;
89 0 : (*ptr)++;
90 : }
91 :
92 340 : if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
93 : {
94 48 : *ptr += 3;
95 48 : dest->sign = NUMERIC_NAN;
96 :
97 : /* Should be nothing left but spaces */
98 48 : while (*(*ptr))
99 : {
100 0 : if (!isspace((unsigned char) *(*ptr)))
101 : {
102 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
103 0 : return -1;
104 : }
105 0 : (*ptr)++;
106 : }
107 :
108 48 : return 0;
109 : }
110 :
111 292 : if (alloc_var(dest, strlen((*ptr))) < 0)
112 0 : return -1;
113 292 : dest->weight = -1;
114 292 : dest->dscale = 0;
115 292 : dest->sign = NUMERIC_POS;
116 :
117 292 : switch (*(*ptr))
118 : {
119 16 : case '+':
120 16 : dest->sign = NUMERIC_POS;
121 16 : (*ptr)++;
122 16 : break;
123 :
124 36 : case '-':
125 36 : dest->sign = NUMERIC_NEG;
126 36 : (*ptr)++;
127 36 : break;
128 : }
129 :
130 292 : if (*(*ptr) == '.')
131 : {
132 40 : have_dp = true;
133 40 : (*ptr)++;
134 : }
135 :
136 292 : if (!isdigit((unsigned char) *(*ptr)))
137 : {
138 8 : errno = PGTYPES_NUM_BAD_NUMERIC;
139 8 : return -1;
140 : }
141 :
142 1836 : while (*(*ptr))
143 : {
144 1612 : if (isdigit((unsigned char) *(*ptr)))
145 : {
146 1368 : dest->digits[i++] = *(*ptr)++ - '0';
147 1368 : if (!have_dp)
148 872 : dest->weight++;
149 : else
150 496 : dest->dscale++;
151 : }
152 244 : else if (*(*ptr) == '.')
153 : {
154 184 : if (have_dp)
155 : {
156 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
157 0 : return -1;
158 : }
159 184 : have_dp = true;
160 184 : (*ptr)++;
161 : }
162 : else
163 60 : break;
164 : }
165 284 : dest->ndigits = i;
166 :
167 : /* Handle exponent, if any */
168 284 : if (*(*ptr) == 'e' || *(*ptr) == 'E')
169 : {
170 : long exponent;
171 : char *endptr;
172 :
173 60 : (*ptr)++;
174 60 : exponent = strtol(*ptr, &endptr, 10);
175 60 : if (endptr == (*ptr))
176 : {
177 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
178 0 : return -1;
179 : }
180 60 : (*ptr) = endptr;
181 60 : if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
182 : {
183 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
184 0 : return -1;
185 : }
186 60 : dest->weight += (int) exponent;
187 60 : dest->dscale -= (int) exponent;
188 60 : if (dest->dscale < 0)
189 28 : dest->dscale = 0;
190 : }
191 :
192 : /* Should be nothing left but spaces */
193 284 : while (*(*ptr))
194 : {
195 0 : if (!isspace((unsigned char) *(*ptr)))
196 : {
197 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
198 0 : return -1;
199 : }
200 0 : (*ptr)++;
201 : }
202 :
203 : /* Strip any leading zeroes */
204 384 : while (dest->ndigits > 0 && *(dest->digits) == 0)
205 : {
206 100 : (dest->digits)++;
207 100 : (dest->weight)--;
208 100 : (dest->ndigits)--;
209 : }
210 284 : if (dest->ndigits == 0)
211 32 : dest->weight = 0;
212 :
213 284 : dest->rscale = dest->dscale;
214 284 : 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 *
226 7848 : get_str_from_var(numeric *var, int dscale)
227 : {
228 : char *str;
229 : char *cp;
230 : int i;
231 : int d;
232 :
233 7848 : if (var->sign == NUMERIC_NAN)
234 : {
235 20 : str = (char *) pgtypes_alloc(4);
236 20 : if (str == NULL)
237 0 : return NULL;
238 20 : sprintf(str, "NaN");
239 20 : return str;
240 : }
241 :
242 : /*
243 : * Check if we must round up before printing the value and do so.
244 : */
245 7828 : i = dscale + var->weight + 1;
246 7828 : if (i >= 0 && var->ndigits > i)
247 1196 : {
248 1196 : int carry = (var->digits[i] > 4) ? 1 : 0;
249 :
250 1196 : var->ndigits = i;
251 :
252 5892 : while (carry)
253 : {
254 4696 : carry += var->digits[--i];
255 4696 : var->digits[i] = carry % 10;
256 4696 : carry /= 10;
257 : }
258 :
259 1196 : if (i < 0)
260 : {
261 80 : var->digits--;
262 80 : var->ndigits++;
263 80 : var->weight++;
264 : }
265 : }
266 : else
267 6632 : var->ndigits = Max(0, Min(i, var->ndigits));
268 :
269 : /*
270 : * Allocate space for the result
271 : */
272 7828 : if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
273 0 : return NULL;
274 7828 : cp = str;
275 :
276 : /*
277 : * Output a dash for negative values
278 : */
279 7828 : if (var->sign == NUMERIC_NEG)
280 2592 : *cp++ = '-';
281 :
282 : /*
283 : * Output all digits before the decimal point
284 : */
285 7828 : i = Max(var->weight, 0);
286 7828 : d = 0;
287 :
288 330556 : while (i >= 0)
289 : {
290 322728 : if (i <= var->weight && d < var->ndigits)
291 141976 : *cp++ = var->digits[d++] + '0';
292 : else
293 180752 : *cp++ = '0';
294 322728 : i--;
295 : }
296 :
297 : /*
298 : * If requested, output a decimal point and all the digits that follow it.
299 : */
300 7828 : if (dscale > 0)
301 : {
302 7140 : *cp++ = '.';
303 188832 : while (i >= -dscale)
304 : {
305 181692 : if (i <= var->weight && d < var->ndigits)
306 29480 : *cp++ = var->digits[d++] + '0';
307 : else
308 152212 : *cp++ = '0';
309 181692 : i--;
310 : }
311 : }
312 :
313 : /*
314 : * terminate the string and return it
315 : */
316 7828 : *cp = '\0';
317 7828 : return str;
318 : }
319 :
320 : numeric *
321 340 : PGTYPESnumeric_from_asc(char *str, char **endptr)
322 : {
323 340 : numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
324 : int ret;
325 :
326 : char *realptr;
327 340 : char **ptr = (endptr != NULL) ? endptr : &realptr;
328 :
329 340 : if (!value)
330 0 : return NULL;
331 :
332 340 : ret = set_var_from_str(str, ptr, value);
333 340 : if (ret)
334 : {
335 8 : PGTYPESnumeric_free(value);
336 8 : return NULL;
337 : }
338 :
339 332 : return value;
340 : }
341 :
342 : char *
343 7736 : PGTYPESnumeric_to_asc(numeric *num, int dscale)
344 : {
345 7736 : numeric *numcopy = PGTYPESnumeric_new();
346 : char *s;
347 :
348 7736 : if (numcopy == NULL)
349 0 : return NULL;
350 :
351 7736 : if (PGTYPESnumeric_copy(num, numcopy) < 0)
352 : {
353 0 : PGTYPESnumeric_free(numcopy);
354 0 : return NULL;
355 : }
356 :
357 7736 : if (dscale < 0)
358 224 : dscale = num->dscale;
359 :
360 : /* get_str_from_var may change its argument */
361 7736 : s = get_str_from_var(numcopy, dscale);
362 7736 : PGTYPESnumeric_free(numcopy);
363 7736 : 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
374 19952 : zero_var(numeric *var)
375 : {
376 19952 : digitbuf_free(var->buf);
377 19952 : var->buf = NULL;
378 19952 : var->digits = NULL;
379 19952 : var->ndigits = 0;
380 19952 : var->weight = 0; /* by convention; doesn't really matter */
381 19952 : var->sign = NUMERIC_POS; /* anything but NAN... */
382 19952 : }
383 :
384 : void
385 26864 : PGTYPESnumeric_free(numeric *var)
386 : {
387 26864 : digitbuf_free(var->buf);
388 26864 : free(var);
389 26864 : }
390 :
391 : void
392 184 : PGTYPESdecimal_free(decimal *var)
393 : {
394 184 : free(var);
395 184 : }
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
407 95048 : cmp_abs(numeric *var1, numeric *var2)
408 : {
409 95048 : int i1 = 0;
410 95048 : int i2 = 0;
411 95048 : int w1 = var1->weight;
412 95048 : int w2 = var2->weight;
413 : int stat;
414 :
415 95048 : while (w1 > w2 && i1 < var1->ndigits)
416 : {
417 860 : if (var1->digits[i1++] != 0)
418 860 : return 1;
419 0 : w1--;
420 : }
421 119844 : while (w2 > w1 && i2 < var2->ndigits)
422 : {
423 32392 : if (var2->digits[i2++] != 0)
424 6736 : return -1;
425 25656 : w2--;
426 : }
427 :
428 87452 : if (w1 == w2)
429 : {
430 156648 : while (i1 < var1->ndigits && i2 < var2->ndigits)
431 : {
432 153312 : stat = var1->digits[i1++] - var2->digits[i2++];
433 153312 : if (stat)
434 : {
435 83916 : if (stat > 0)
436 45192 : return 1;
437 38724 : return -1;
438 : }
439 : }
440 : }
441 :
442 3864 : while (i1 < var1->ndigits)
443 : {
444 1700 : if (var1->digits[i1++] != 0)
445 1372 : return 1;
446 : }
447 3052 : while (i2 < var2->ndigits)
448 : {
449 2244 : if (var2->digits[i2++] != 0)
450 1356 : return -1;
451 : }
452 :
453 808 : 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
465 1692 : 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;
476 1692 : int carry = 0;
477 :
478 : /* copy these values into local vars for speed in inner loop */
479 1692 : int var1ndigits = var1->ndigits;
480 1692 : int var2ndigits = var2->ndigits;
481 1692 : NumericDigit *var1digits = var1->digits;
482 1692 : NumericDigit *var2digits = var2->digits;
483 :
484 1692 : res_weight = Max(var1->weight, var2->weight) + 1;
485 1692 : res_rscale = Max(var1->rscale, var2->rscale);
486 1692 : res_dscale = Max(var1->dscale, var2->dscale);
487 1692 : res_ndigits = res_rscale + res_weight + 1;
488 1692 : if (res_ndigits <= 0)
489 0 : res_ndigits = 1;
490 :
491 1692 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
492 0 : return -1;
493 1692 : res_digits = res_buf;
494 :
495 1692 : i1 = res_rscale + var1->weight + 1;
496 1692 : i2 = res_rscale + var2->weight + 1;
497 197860 : for (i = res_ndigits - 1; i >= 0; i--)
498 : {
499 196168 : i1--;
500 196168 : i2--;
501 196168 : if (i1 >= 0 && i1 < var1ndigits)
502 10124 : carry += var1digits[i1];
503 196168 : if (i2 >= 0 && i2 < var2ndigits)
504 10120 : carry += var2digits[i2];
505 :
506 196168 : if (carry >= 10)
507 : {
508 864 : res_digits[i] = carry - 10;
509 864 : carry = 1;
510 : }
511 : else
512 : {
513 195304 : res_digits[i] = carry;
514 195304 : carry = 0;
515 : }
516 : }
517 :
518 9840 : while (res_ndigits > 0 && *res_digits == 0)
519 : {
520 8148 : res_digits++;
521 8148 : res_weight--;
522 8148 : res_ndigits--;
523 : }
524 12088 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
525 10396 : res_ndigits--;
526 :
527 1692 : if (res_ndigits == 0)
528 8 : res_weight = 0;
529 :
530 1692 : digitbuf_free(result->buf);
531 1692 : result->ndigits = res_ndigits;
532 1692 : result->buf = res_buf;
533 1692 : result->digits = res_digits;
534 1692 : result->weight = res_weight;
535 1692 : result->rscale = res_rscale;
536 1692 : result->dscale = res_dscale;
537 :
538 1692 : 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
553 47924 : 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;
564 47924 : int borrow = 0;
565 :
566 : /* copy these values into local vars for speed in inner loop */
567 47924 : int var1ndigits = var1->ndigits;
568 47924 : int var2ndigits = var2->ndigits;
569 47924 : NumericDigit *var1digits = var1->digits;
570 47924 : NumericDigit *var2digits = var2->digits;
571 :
572 47924 : res_weight = var1->weight;
573 47924 : res_rscale = Max(var1->rscale, var2->rscale);
574 47924 : res_dscale = Max(var1->dscale, var2->dscale);
575 47924 : res_ndigits = res_rscale + res_weight + 1;
576 47924 : if (res_ndigits <= 0)
577 0 : res_ndigits = 1;
578 :
579 47924 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
580 0 : return -1;
581 47924 : res_digits = res_buf;
582 :
583 47924 : i1 = res_rscale + var1->weight + 1;
584 47924 : i2 = res_rscale + var2->weight + 1;
585 727980 : for (i = res_ndigits - 1; i >= 0; i--)
586 : {
587 680056 : i1--;
588 680056 : i2--;
589 680056 : if (i1 >= 0 && i1 < var1ndigits)
590 408328 : borrow += var1digits[i1];
591 680056 : if (i2 >= 0 && i2 < var2ndigits)
592 406496 : borrow -= var2digits[i2];
593 :
594 680056 : if (borrow < 0)
595 : {
596 331356 : res_digits[i] = borrow + 10;
597 331356 : borrow = -1;
598 : }
599 : else
600 : {
601 348700 : res_digits[i] = borrow;
602 348700 : borrow = 0;
603 : }
604 : }
605 :
606 101384 : while (res_ndigits > 0 && *res_digits == 0)
607 : {
608 53460 : res_digits++;
609 53460 : res_weight--;
610 53460 : res_ndigits--;
611 : }
612 103716 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
613 55792 : res_ndigits--;
614 :
615 47924 : if (res_ndigits == 0)
616 0 : res_weight = 0;
617 :
618 47924 : digitbuf_free(result->buf);
619 47924 : result->ndigits = res_ndigits;
620 47924 : result->buf = res_buf;
621 47924 : result->digits = res_digits;
622 47924 : result->weight = res_weight;
623 47924 : result->rscale = res_rscale;
624 47924 : result->dscale = res_dscale;
625 :
626 47924 : 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
637 1692 : PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
638 : {
639 : /*
640 : * Decide on the signs of the two variables what to do
641 : */
642 1692 : if (var1->sign == NUMERIC_POS)
643 : {
644 1228 : if (var2->sign == NUMERIC_POS)
645 : {
646 : /*
647 : * Both are positive result = +(ABS(var1) + ABS(var2))
648 : */
649 892 : if (add_abs(var1, var2, result) != 0)
650 0 : return -1;
651 892 : result->sign = NUMERIC_POS;
652 : }
653 : else
654 : {
655 : /*
656 : * var1 is positive, var2 is negative Must compare absolute values
657 : */
658 336 : switch (cmp_abs(var1, var2))
659 : {
660 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 :
671 184 : case 1:
672 : /* ----------
673 : * ABS(var1) > ABS(var2)
674 : * result = +(ABS(var1) - ABS(var2))
675 : * ----------
676 : */
677 184 : if (sub_abs(var1, var2, result) != 0)
678 0 : return -1;
679 184 : result->sign = NUMERIC_POS;
680 184 : break;
681 :
682 152 : case -1:
683 : /* ----------
684 : * ABS(var1) < ABS(var2)
685 : * result = -(ABS(var2) - ABS(var1))
686 : * ----------
687 : */
688 152 : if (sub_abs(var2, var1, result) != 0)
689 0 : return -1;
690 152 : result->sign = NUMERIC_NEG;
691 152 : break;
692 : }
693 1228 : }
694 : }
695 : else
696 : {
697 464 : if (var2->sign == NUMERIC_POS)
698 : {
699 : /* ----------
700 : * var1 is negative, var2 is positive
701 : * Must compare absolute values
702 : * ----------
703 : */
704 336 : switch (cmp_abs(var1, var2))
705 : {
706 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 :
717 152 : case 1:
718 : /* ----------
719 : * ABS(var1) > ABS(var2)
720 : * result = -(ABS(var1) - ABS(var2))
721 : * ----------
722 : */
723 152 : if (sub_abs(var1, var2, result) != 0)
724 0 : return -1;
725 152 : result->sign = NUMERIC_NEG;
726 152 : break;
727 :
728 184 : case -1:
729 : /* ----------
730 : * ABS(var1) < ABS(var2)
731 : * result = +(ABS(var2) - ABS(var1))
732 : * ----------
733 : */
734 184 : if (sub_abs(var2, var1, result) != 0)
735 0 : return -1;
736 184 : result->sign = NUMERIC_POS;
737 184 : break;
738 : }
739 336 : }
740 : else
741 : {
742 : /* ----------
743 : * Both are negative
744 : * result = -(ABS(var1) + ABS(var2))
745 : * ----------
746 : */
747 128 : if (add_abs(var1, var2, result) != 0)
748 0 : return -1;
749 128 : result->sign = NUMERIC_NEG;
750 : }
751 : }
752 :
753 1692 : 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
765 1688 : PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
766 : {
767 : /*
768 : * Decide on the signs of the two variables what to do
769 : */
770 1688 : if (var1->sign == NUMERIC_POS)
771 : {
772 1224 : if (var2->sign == NUMERIC_NEG)
773 : {
774 : /* ----------
775 : * var1 is positive, var2 is negative
776 : * result = +(ABS(var1) + ABS(var2))
777 : * ----------
778 : */
779 336 : if (add_abs(var1, var2, result) != 0)
780 0 : return -1;
781 336 : result->sign = NUMERIC_POS;
782 : }
783 : else
784 : {
785 : /* ----------
786 : * Both are positive
787 : * Must compare absolute values
788 : * ----------
789 : */
790 888 : switch (cmp_abs(var1, var2))
791 : {
792 84 : case 0:
793 : /* ----------
794 : * ABS(var1) == ABS(var2)
795 : * result = ZERO
796 : * ----------
797 : */
798 84 : zero_var(result);
799 84 : result->rscale = Max(var1->rscale, var2->rscale);
800 84 : result->dscale = Max(var1->dscale, var2->dscale);
801 84 : break;
802 :
803 404 : case 1:
804 : /* ----------
805 : * ABS(var1) > ABS(var2)
806 : * result = +(ABS(var1) - ABS(var2))
807 : * ----------
808 : */
809 404 : if (sub_abs(var1, var2, result) != 0)
810 0 : return -1;
811 404 : result->sign = NUMERIC_POS;
812 404 : break;
813 :
814 400 : case -1:
815 : /* ----------
816 : * ABS(var1) < ABS(var2)
817 : * result = -(ABS(var2) - ABS(var1))
818 : * ----------
819 : */
820 400 : if (sub_abs(var2, var1, result) != 0)
821 0 : return -1;
822 400 : result->sign = NUMERIC_NEG;
823 400 : break;
824 : }
825 1224 : }
826 : }
827 : else
828 : {
829 464 : if (var2->sign == NUMERIC_NEG)
830 : {
831 : /* ----------
832 : * Both are negative
833 : * Must compare absolute values
834 : * ----------
835 : */
836 128 : switch (cmp_abs(var1, var2))
837 : {
838 32 : case 0:
839 : /* ----------
840 : * ABS(var1) == ABS(var2)
841 : * result = ZERO
842 : * ----------
843 : */
844 32 : zero_var(result);
845 32 : result->rscale = Max(var1->rscale, var2->rscale);
846 32 : result->dscale = Max(var1->dscale, var2->dscale);
847 32 : break;
848 :
849 48 : case 1:
850 : /* ----------
851 : * ABS(var1) > ABS(var2)
852 : * result = -(ABS(var1) - ABS(var2))
853 : * ----------
854 : */
855 48 : if (sub_abs(var1, var2, result) != 0)
856 0 : return -1;
857 48 : result->sign = NUMERIC_NEG;
858 48 : break;
859 :
860 48 : case -1:
861 : /* ----------
862 : * ABS(var1) < ABS(var2)
863 : * result = +(ABS(var2) - ABS(var1))
864 : * ----------
865 : */
866 48 : if (sub_abs(var2, var1, result) != 0)
867 0 : return -1;
868 48 : result->sign = NUMERIC_POS;
869 48 : break;
870 : }
871 128 : }
872 : else
873 : {
874 : /* ----------
875 : * var1 is negative, var2 is positive
876 : * result = -(ABS(var1) + ABS(var2))
877 : * ----------
878 : */
879 336 : if (add_abs(var1, var2, result) != 0)
880 0 : return -1;
881 336 : result->sign = NUMERIC_NEG;
882 : }
883 : }
884 :
885 1688 : 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
896 1692 : 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;
907 1692 : long sum = 0;
908 1692 : int global_rscale = var1->rscale + var2->rscale;
909 :
910 1692 : res_weight = var1->weight + var2->weight + 2;
911 1692 : res_ndigits = var1->ndigits + var2->ndigits + 1;
912 1692 : if (var1->sign == var2->sign)
913 1020 : res_sign = NUMERIC_POS;
914 : else
915 672 : res_sign = NUMERIC_NEG;
916 :
917 1692 : if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
918 0 : return -1;
919 1692 : res_digits = res_buf;
920 1692 : memset(res_digits, 0, res_ndigits);
921 :
922 1692 : ri = res_ndigits;
923 11844 : for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
924 : {
925 10152 : sum = 0;
926 10152 : i = --ri;
927 :
928 72428 : for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
929 : {
930 62276 : sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
931 62276 : res_digits[i--] = sum % 10;
932 62276 : sum /= 10;
933 : }
934 10152 : res_digits[i] = sum;
935 : }
936 :
937 1692 : i = res_weight + global_rscale + 2;
938 1692 : if (i >= 0 && i < res_ndigits)
939 : {
940 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 :
951 5480 : while (res_ndigits > 0 && *res_digits == 0)
952 : {
953 3788 : res_digits++;
954 3788 : res_weight--;
955 3788 : res_ndigits--;
956 : }
957 1716 : while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
958 24 : res_ndigits--;
959 :
960 1692 : if (res_ndigits == 0)
961 : {
962 224 : res_sign = NUMERIC_POS;
963 224 : res_weight = 0;
964 : }
965 :
966 1692 : digitbuf_free(result->buf);
967 1692 : result->buf = res_buf;
968 1692 : result->digits = res_digits;
969 1692 : result->ndigits = res_ndigits;
970 1692 : result->weight = res_weight;
971 1692 : result->rscale = global_rscale;
972 1692 : result->sign = res_sign;
973 1692 : result->dscale = var1->dscale + var2->dscale;
974 :
975 1692 : 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
987 1688 : 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 :
1007 1688 : weight1 = 0; /* values to use if var1 is zero */
1008 1688 : firstdigit1 = 0;
1009 1688 : for (i = 0; i < var1->ndigits; i++)
1010 : {
1011 1572 : firstdigit1 = var1->digits[i];
1012 1572 : if (firstdigit1 != 0)
1013 : {
1014 1572 : weight1 = var1->weight - i;
1015 1572 : break;
1016 : }
1017 : }
1018 :
1019 1688 : weight2 = 0; /* values to use if var2 is zero */
1020 1688 : firstdigit2 = 0;
1021 1688 : for (i = 0; i < var2->ndigits; i++)
1022 : {
1023 1572 : firstdigit2 = var2->digits[i];
1024 1572 : if (firstdigit2 != 0)
1025 : {
1026 1572 : weight2 = var2->weight - i;
1027 1572 : 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 1688 : qweight = weight1 - weight2;
1036 1688 : if (firstdigit1 <= firstdigit2)
1037 1016 : qweight--;
1038 :
1039 : /* Select display scale */
1040 1688 : res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1041 1688 : res_dscale = Max(res_dscale, var1->dscale);
1042 1688 : res_dscale = Max(res_dscale, var2->dscale);
1043 1688 : res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1044 1688 : res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1045 :
1046 : /* Select result scale */
1047 1688 : *rscale = res_dscale + 4;
1048 :
1049 1688 : return res_dscale;
1050 : }
1051 :
1052 : int
1053 1688 : 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;
1069 1688 : int stat = 0;
1070 : int rscale;
1071 1688 : int res_dscale = select_div_scale(var1, var2, &rscale);
1072 1688 : int err = -1;
1073 : NumericDigit *tmp_buf;
1074 :
1075 : /*
1076 : * First of all division by zero check
1077 : */
1078 1688 : ndigits_tmp = var2->ndigits + 1;
1079 1688 : if (ndigits_tmp == 1)
1080 : {
1081 116 : errno = PGTYPES_NUM_DIVIDE_ZERO;
1082 116 : return -1;
1083 : }
1084 :
1085 : /*
1086 : * Determine the result sign, weight and number of digits to calculate
1087 : */
1088 1572 : if (var1->sign == var2->sign)
1089 932 : res_sign = NUMERIC_POS;
1090 : else
1091 640 : res_sign = NUMERIC_NEG;
1092 1572 : res_weight = var1->weight - var2->weight + 1;
1093 1572 : res_ndigits = rscale + res_weight;
1094 1572 : if (res_ndigits <= 0)
1095 0 : res_ndigits = 1;
1096 :
1097 : /*
1098 : * Now result zero check
1099 : */
1100 1572 : if (var1->ndigits == 0)
1101 : {
1102 108 : zero_var(result);
1103 108 : result->rscale = rscale;
1104 108 : return 0;
1105 : }
1106 :
1107 : /*
1108 : * Initialize local variables
1109 : */
1110 1464 : init_var(÷nd);
1111 14640 : for (int i = 1; i < 10; i++)
1112 13176 : init_var(&divisor[i]);
1113 :
1114 : /*
1115 : * Make a copy of the divisor which has one leading zero digit
1116 : */
1117 1464 : divisor[1].ndigits = ndigits_tmp;
1118 1464 : divisor[1].rscale = var2->ndigits;
1119 1464 : divisor[1].sign = NUMERIC_POS;
1120 1464 : divisor[1].buf = digitbuf_alloc(ndigits_tmp);
1121 1464 : if (divisor[1].buf == NULL)
1122 0 : goto done;
1123 1464 : divisor[1].digits = divisor[1].buf;
1124 1464 : divisor[1].digits[0] = 0;
1125 1464 : memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1126 :
1127 : /*
1128 : * Make a copy of the dividend
1129 : */
1130 1464 : dividend.ndigits = var1->ndigits;
1131 1464 : dividend.weight = 0;
1132 1464 : dividend.rscale = var1->ndigits;
1133 1464 : dividend.sign = NUMERIC_POS;
1134 1464 : dividend.buf = digitbuf_alloc(var1->ndigits);
1135 1464 : if (dividend.buf == NULL)
1136 0 : goto done;
1137 1464 : dividend.digits = dividend.buf;
1138 1464 : 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 : */
1145 1464 : tmp_buf = digitbuf_alloc(res_ndigits + 2);
1146 1464 : if (tmp_buf == NULL)
1147 0 : goto done;
1148 1464 : digitbuf_free(result->buf);
1149 1464 : result->buf = tmp_buf;
1150 1464 : res_digits = result->buf;
1151 1464 : result->digits = res_digits;
1152 1464 : result->ndigits = res_ndigits;
1153 1464 : result->weight = res_weight;
1154 1464 : result->rscale = rscale;
1155 1464 : result->sign = res_sign;
1156 1464 : res_digits[0] = 0;
1157 :
1158 1464 : first_div = divisor[1].digits[1] * 10;
1159 1464 : if (ndigits_tmp > 2)
1160 1032 : first_div += divisor[1].digits[2];
1161 :
1162 1464 : first_have = 0;
1163 1464 : first_nextdigit = 0;
1164 :
1165 1464 : weight_tmp = 1;
1166 1464 : rscale_tmp = divisor[1].rscale;
1167 :
1168 55160 : for (ri = 0; ri <= res_ndigits; ri++)
1169 : {
1170 54228 : first_have = first_have * 10;
1171 54228 : if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1172 50332 : first_have += dividend.digits[first_nextdigit];
1173 54228 : first_nextdigit++;
1174 :
1175 54228 : guess = (first_have * 10) / first_div + 1;
1176 54228 : if (guess > 9)
1177 5892 : guess = 9;
1178 :
1179 100024 : while (guess > 0)
1180 : {
1181 92680 : if (divisor[guess].buf == NULL)
1182 : {
1183 : int i;
1184 9108 : long sum = 0;
1185 :
1186 9108 : memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
1187 9108 : divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
1188 9108 : if (divisor[guess].buf == NULL)
1189 0 : goto done;
1190 9108 : divisor[guess].digits = divisor[guess].buf;
1191 82060 : for (i = divisor[1].ndigits - 1; i >= 0; i--)
1192 : {
1193 72952 : sum += divisor[1].digits[i] * guess;
1194 72952 : divisor[guess].digits[i] = sum % 10;
1195 72952 : sum /= 10;
1196 : }
1197 : }
1198 :
1199 92680 : divisor[guess].weight = weight_tmp;
1200 92680 : divisor[guess].rscale = rscale_tmp;
1201 :
1202 92680 : stat = cmp_abs(÷nd, &divisor[guess]);
1203 92680 : if (stat >= 0)
1204 46884 : break;
1205 :
1206 45796 : guess--;
1207 : }
1208 :
1209 54228 : res_digits[ri + 1] = guess;
1210 54228 : if (stat == 0)
1211 : {
1212 532 : ri++;
1213 532 : break;
1214 : }
1215 :
1216 53696 : weight_tmp--;
1217 53696 : rscale_tmp++;
1218 :
1219 53696 : if (guess == 0)
1220 7344 : continue;
1221 :
1222 46352 : if (sub_abs(÷nd, &divisor[guess], ÷nd) != 0)
1223 0 : goto done;
1224 :
1225 46352 : first_nextdigit = dividend.weight - weight_tmp;
1226 46352 : first_have = 0;
1227 46352 : if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1228 31840 : first_have = dividend.digits[first_nextdigit];
1229 46352 : first_nextdigit++;
1230 : }
1231 :
1232 1464 : result->ndigits = ri + 1;
1233 1464 : if (ri == res_ndigits + 1)
1234 : {
1235 932 : int carry = (res_digits[ri] > 4) ? 1 : 0;
1236 :
1237 932 : result->ndigits = ri;
1238 932 : res_digits[ri] = 0;
1239 :
1240 1544 : while (carry && ri > 0)
1241 : {
1242 612 : carry += res_digits[--ri];
1243 612 : res_digits[ri] = carry % 10;
1244 612 : carry /= 10;
1245 : }
1246 : }
1247 :
1248 3560 : while (result->ndigits > 0 && *(result->digits) == 0)
1249 : {
1250 2096 : (result->digits)++;
1251 2096 : (result->weight)--;
1252 2096 : (result->ndigits)--;
1253 : }
1254 1776 : while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1255 312 : (result->ndigits)--;
1256 1464 : if (result->ndigits == 0)
1257 0 : result->sign = NUMERIC_POS;
1258 :
1259 1464 : result->dscale = res_dscale;
1260 1464 : err = 0; /* if we've made it this far, return success */
1261 :
1262 1464 : done:
1263 :
1264 : /*
1265 : * Tidy up
1266 : */
1267 1464 : if (dividend.buf != NULL)
1268 1464 : digitbuf_free(dividend.buf);
1269 :
1270 14640 : for (int i = 1; i < 10; i++)
1271 : {
1272 13176 : if (divisor[i].buf != NULL)
1273 10572 : digitbuf_free(divisor[i].buf);
1274 : }
1275 :
1276 1464 : return err;
1277 : }
1278 :
1279 :
1280 : int
1281 1132 : 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 */
1286 1132 : if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
1287 552 : return cmp_abs(var1, var2);
1288 :
1289 : /* both are negative: return the inverse of the normal comparison */
1290 580 : if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1291 : {
1292 : /*
1293 : * instead of inverting the result, we invert the parameter ordering
1294 : */
1295 128 : return cmp_abs(var2, var1);
1296 : }
1297 :
1298 : /* one is positive, one is negative: trivial */
1299 452 : if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
1300 160 : return 1;
1301 292 : if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
1302 176 : return -1;
1303 :
1304 116 : errno = PGTYPES_NUM_BAD_NUMERIC;
1305 116 : return INT_MAX;
1306 : }
1307 :
1308 : int
1309 144 : PGTYPESnumeric_from_int(signed int int_val, numeric *var)
1310 : {
1311 : /* implicit conversion */
1312 144 : signed long int long_int = int_val;
1313 :
1314 144 : return PGTYPESnumeric_from_long(long_int, var);
1315 : }
1316 :
1317 : int
1318 232 : 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 :
1328 232 : int size = 0;
1329 : int i;
1330 232 : signed long int abs_long_val = long_val;
1331 : signed long int extract;
1332 : signed long int reach_limit;
1333 :
1334 232 : if (abs_long_val < 0)
1335 : {
1336 48 : abs_long_val *= -1;
1337 48 : var->sign = NUMERIC_NEG;
1338 : }
1339 : else
1340 184 : var->sign = NUMERIC_POS;
1341 :
1342 232 : reach_limit = 1;
1343 : do
1344 : {
1345 328 : size++;
1346 328 : reach_limit *= 10;
1347 328 : } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
1348 :
1349 232 : if (reach_limit > LONG_MAX / 10)
1350 : {
1351 : /* add the first digit and a .0 */
1352 0 : size += 2;
1353 : }
1354 : else
1355 : {
1356 : /* always add a .0 */
1357 232 : size++;
1358 232 : reach_limit /= 10;
1359 : }
1360 :
1361 232 : if (alloc_var(var, size) < 0)
1362 0 : return -1;
1363 :
1364 232 : var->rscale = 1;
1365 232 : var->dscale = 1;
1366 232 : var->weight = size - 2;
1367 :
1368 232 : i = 0;
1369 : do
1370 : {
1371 296 : extract = abs_long_val - (abs_long_val % reach_limit);
1372 296 : var->digits[i] = extract / reach_limit;
1373 296 : abs_long_val -= extract;
1374 296 : i++;
1375 296 : 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 : */
1382 296 : } while (abs_long_val > 0);
1383 :
1384 232 : return 0;
1385 : }
1386 :
1387 : int
1388 8040 : PGTYPESnumeric_copy(numeric *src, numeric *dst)
1389 : {
1390 : int i;
1391 :
1392 8040 : if (dst == NULL)
1393 0 : return -1;
1394 8040 : zero_var(dst);
1395 :
1396 8040 : dst->weight = src->weight;
1397 8040 : dst->rscale = src->rscale;
1398 8040 : dst->dscale = src->dscale;
1399 8040 : dst->sign = src->sign;
1400 :
1401 8040 : if (alloc_var(dst, src->ndigits) != 0)
1402 0 : return -1;
1403 :
1404 269512 : for (i = 0; i < src->ndigits; i++)
1405 261472 : dst->digits[i] = src->digits[i];
1406 :
1407 8040 : return 0;
1408 : }
1409 :
1410 : int
1411 0 : PGTYPESnumeric_from_double(double d, numeric *dst)
1412 : {
1413 : char buffer[DBL_DIG + 100];
1414 : numeric *tmp;
1415 : int i;
1416 :
1417 0 : if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
1418 0 : return -1;
1419 :
1420 0 : if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1421 0 : return -1;
1422 0 : i = PGTYPESnumeric_copy(tmp, dst);
1423 0 : PGTYPESnumeric_free(tmp);
1424 0 : if (i != 0)
1425 0 : return -1;
1426 :
1427 0 : errno = 0;
1428 0 : return 0;
1429 : }
1430 :
1431 : static int
1432 112 : numericvar_to_double(numeric *var, double *dp)
1433 : {
1434 : char *tmp;
1435 : double val;
1436 : char *endptr;
1437 112 : numeric *varcopy = PGTYPESnumeric_new();
1438 :
1439 112 : if (varcopy == NULL)
1440 0 : return -1;
1441 :
1442 112 : if (PGTYPESnumeric_copy(var, varcopy) < 0)
1443 : {
1444 0 : PGTYPESnumeric_free(varcopy);
1445 0 : return -1;
1446 : }
1447 :
1448 112 : tmp = get_str_from_var(varcopy, varcopy->dscale);
1449 112 : PGTYPESnumeric_free(varcopy);
1450 :
1451 112 : if (tmp == NULL)
1452 0 : return -1;
1453 :
1454 : /*
1455 : * strtod does not reset errno to 0 in case of success.
1456 : */
1457 112 : errno = 0;
1458 112 : val = strtod(tmp, &endptr);
1459 112 : if (errno == ERANGE)
1460 : {
1461 8 : free(tmp);
1462 8 : if (val == 0)
1463 0 : errno = PGTYPES_NUM_UNDERFLOW;
1464 : else
1465 8 : errno = PGTYPES_NUM_OVERFLOW;
1466 8 : return -1;
1467 : }
1468 :
1469 : /* can't free tmp yet, endptr points still into it */
1470 104 : if (*endptr != '\0')
1471 : {
1472 : /* shouldn't happen ... */
1473 0 : free(tmp);
1474 0 : errno = PGTYPES_NUM_BAD_NUMERIC;
1475 0 : return -1;
1476 : }
1477 104 : free(tmp);
1478 104 : *dp = val;
1479 104 : return 0;
1480 : }
1481 :
1482 : int
1483 112 : PGTYPESnumeric_to_double(numeric *nv, double *dp)
1484 : {
1485 : double tmp;
1486 :
1487 112 : if (numericvar_to_double(nv, &tmp) != 0)
1488 8 : return -1;
1489 104 : *dp = tmp;
1490 104 : return 0;
1491 : }
1492 :
1493 : int
1494 132 : PGTYPESnumeric_to_int(numeric *nv, int *ip)
1495 : {
1496 : long l;
1497 : int i;
1498 :
1499 132 : if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
1500 28 : return i;
1501 :
1502 : /* silence compilers that might complain about useless tests */
1503 : #if SIZEOF_LONG > SIZEOF_INT
1504 :
1505 104 : if (l < INT_MIN || l > INT_MAX)
1506 : {
1507 0 : errno = PGTYPES_NUM_OVERFLOW;
1508 0 : return -1;
1509 : }
1510 :
1511 : #endif
1512 :
1513 104 : *ip = (int) l;
1514 104 : return 0;
1515 : }
1516 :
1517 : int
1518 256 : PGTYPESnumeric_to_long(numeric *nv, long *lp)
1519 : {
1520 256 : char *s = PGTYPESnumeric_to_asc(nv, 0);
1521 : char *endptr;
1522 :
1523 256 : if (s == NULL)
1524 0 : return -1;
1525 :
1526 256 : errno = 0;
1527 256 : *lp = strtol(s, &endptr, 10);
1528 256 : if (endptr == s)
1529 : {
1530 : /* this should not happen actually */
1531 0 : free(s);
1532 0 : return -1;
1533 : }
1534 256 : free(s);
1535 256 : if (errno == ERANGE)
1536 : {
1537 56 : if (*lp == LONG_MIN)
1538 0 : errno = PGTYPES_NUM_UNDERFLOW;
1539 : else
1540 56 : errno = PGTYPES_NUM_OVERFLOW;
1541 56 : return -1;
1542 : }
1543 200 : return 0;
1544 : }
1545 :
1546 : int
1547 3336 : PGTYPESnumeric_to_decimal(numeric *src, decimal *dst)
1548 : {
1549 : int i;
1550 :
1551 3336 : if (src->ndigits > DECSIZE)
1552 : {
1553 648 : errno = PGTYPES_NUM_OVERFLOW;
1554 648 : return -1;
1555 : }
1556 :
1557 2688 : dst->weight = src->weight;
1558 2688 : dst->rscale = src->rscale;
1559 2688 : dst->dscale = src->dscale;
1560 2688 : dst->sign = src->sign;
1561 2688 : dst->ndigits = src->ndigits;
1562 :
1563 27224 : for (i = 0; i < src->ndigits; i++)
1564 24536 : dst->digits[i] = src->digits[i];
1565 :
1566 2688 : return 0;
1567 : }
1568 :
1569 : int
1570 11688 : PGTYPESnumeric_from_decimal(decimal *src, numeric *dst)
1571 : {
1572 : int i;
1573 :
1574 11688 : zero_var(dst);
1575 :
1576 11688 : dst->weight = src->weight;
1577 11688 : dst->rscale = src->rscale;
1578 11688 : dst->dscale = src->dscale;
1579 11688 : dst->sign = src->sign;
1580 :
1581 11688 : if (alloc_var(dst, src->ndigits) != 0)
1582 0 : return -1;
1583 :
1584 83628 : for (i = 0; i < src->ndigits; i++)
1585 71940 : dst->digits[i] = src->digits[i];
1586 :
1587 11688 : return 0;
1588 : }
|