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