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