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