]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/numeric.c
5160f690c1e363300896cf6b1910d0cc81ba0093
[postgresql] / src / backend / utils / adt / numeric.c
1 /* ----------
2  * numeric.c
3  *
4  *      An exact numeric data type for the Postgres database system
5  *
6  *      1998 Jan Wieck
7  *
8  * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.45 2001/10/13 23:32:33 tgl Exp $
9  *
10  * ----------
11  */
12
13 #include "postgres.h"
14
15 #include <ctype.h>
16 #include <float.h>
17 #include <math.h>
18 #include <errno.h>
19 #include <sys/types.h>
20
21 #include "utils/array.h"
22 #include "utils/builtins.h"
23 #include "utils/int8.h"
24 #include "utils/numeric.h"
25
26 /* ----------
27  * Uncomment the following to enable compilation of dump_numeric()
28  * and dump_var() and to get a dump of any result produced by make_result().
29  * ----------
30 #define NUMERIC_DEBUG
31  */
32
33
34 /* ----------
35  * Local definitions
36  * ----------
37  */
38 #ifndef MIN
39 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
40 #endif
41 #ifndef MAX
42 #define MAX(a,b) (((a)>(b)) ? (a) : (b))
43 #endif
44
45 #ifndef NAN
46 #define NAN             (0.0/0.0)
47 #endif
48
49
50 /* ----------
51  * Local data types
52  *
53  * Note: the first digit of a NumericVar's value is assumed to be multiplied
54  * by 10 ** weight.  Another way to say it is that there are weight+1 digits
55  * before the decimal point.  It is possible to have weight < 0.
56  *
57  * The value represented by a NumericVar is determined by the sign, weight,
58  * ndigits, and digits[] array.  The rscale and dscale are carried along,
59  * but they are just auxiliary information until rounding is done before
60  * final storage or display.  (Scales are the number of digits wanted
61  * *after* the decimal point.  Scales are always >= 0.)
62  *
63  * buf points at the physical start of the palloc'd digit buffer for the
64  * NumericVar.  digits points at the first digit in actual use (the one
65  * with the specified weight).  We normally leave an unused byte or two
66  * (preset to zeroes) between buf and digits, so that there is room to store
67  * a carry out of the top digit without special pushups.  We just need to
68  * decrement digits (and increment weight) to make room for the carry digit.
69  *
70  * If buf is NULL then the digit buffer isn't actually palloc'd and should
71  * not be freed --- see the constants below for an example.
72  *
73  * NB: All the variable-level functions are written in a style that makes it
74  * possible to give one and the same variable as argument and destination.
75  * This is feasible because the digit buffer is separate from the variable.
76  * ----------
77  */
78 typedef unsigned char NumericDigit;
79
80 typedef struct NumericVar
81 {
82         int                     ndigits;                /* number of digits in digits[] - can be
83                                                                  * 0! */
84         int                     weight;                 /* weight of first digit */
85         int                     rscale;                 /* result scale */
86         int                     dscale;                 /* display scale */
87         int                     sign;                   /* NUMERIC_POS, NUMERIC_NEG, or
88                                                                  * NUMERIC_NAN */
89         NumericDigit *buf;                      /* start of palloc'd space for digits[] */
90         NumericDigit *digits;           /* decimal digits */
91 } NumericVar;
92
93
94 /* ----------
95  * Local data
96  * ----------
97  */
98 static int      global_rscale = NUMERIC_MIN_RESULT_SCALE;
99
100 /* ----------
101  * Some preinitialized variables we need often
102  * ----------
103  */
104 static NumericDigit const_zero_data[1] = {0};
105 static NumericVar const_zero =
106 {0, 0, 0, 0, NUMERIC_POS, NULL, const_zero_data};
107
108 static NumericDigit const_one_data[1] = {1};
109 static NumericVar const_one =
110 {1, 0, 0, 0, NUMERIC_POS, NULL, const_one_data};
111
112 static NumericDigit const_two_data[1] = {2};
113 static NumericVar const_two =
114 {1, 0, 0, 0, NUMERIC_POS, NULL, const_two_data};
115
116 static NumericVar const_nan =
117 {0, 0, 0, 0, NUMERIC_NAN, NULL, NULL};
118
119
120
121 /* ----------
122  * Local functions
123  * ----------
124  */
125
126 #ifdef NUMERIC_DEBUG
127 static void dump_numeric(char *str, Numeric num);
128 static void dump_var(char *str, NumericVar *var);
129
130 #else
131 #define dump_numeric(s,n)
132 #define dump_var(s,v)
133 #endif
134
135 #define digitbuf_alloc(size)  ((NumericDigit *) palloc(size))
136 #define digitbuf_free(buf)      \
137         do { \
138                  if ((buf) != NULL) \
139                          pfree(buf); \
140         } while (0)
141
142 #define init_var(v)             memset(v,0,sizeof(NumericVar))
143 static void alloc_var(NumericVar *var, int ndigits);
144 static void free_var(NumericVar *var);
145 static void zero_var(NumericVar *var);
146
147 static void set_var_from_str(char *str, NumericVar *dest);
148 static void set_var_from_num(Numeric value, NumericVar *dest);
149 static void set_var_from_var(NumericVar *value, NumericVar *dest);
150 static char *get_str_from_var(NumericVar *var, int dscale);
151
152 static Numeric make_result(NumericVar *var);
153
154 static void apply_typmod(NumericVar *var, int32 typmod);
155
156 static int      cmp_numerics(Numeric num1, Numeric num2);
157 static int      cmp_var(NumericVar *var1, NumericVar *var2);
158 static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
159 static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
160 static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
161 static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
162 static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
163 static void ceil_var(NumericVar *var, NumericVar *result);
164 static void floor_var(NumericVar *var, NumericVar *result);
165
166 static void sqrt_var(NumericVar *arg, NumericVar *result);
167 static void exp_var(NumericVar *arg, NumericVar *result);
168 static void ln_var(NumericVar *arg, NumericVar *result);
169 static void log_var(NumericVar *base, NumericVar *num, NumericVar *result);
170 static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result);
171
172 static int      cmp_abs(NumericVar *var1, NumericVar *var2);
173 static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
174 static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
175
176
177
178 /* ----------------------------------------------------------------------
179  *
180  * Input-, output- and rounding-functions
181  *
182  * ----------------------------------------------------------------------
183  */
184
185
186 /* ----------
187  * numeric_in() -
188  *
189  *      Input function for numeric data type
190  * ----------
191  */
192 Datum
193 numeric_in(PG_FUNCTION_ARGS)
194 {
195         char       *str = PG_GETARG_CSTRING(0);
196 #ifdef NOT_USED
197         Oid                     typelem = PG_GETARG_OID(1);
198 #endif
199         int32           typmod = PG_GETARG_INT32(2);
200         NumericVar      value;
201         Numeric         res;
202
203         /*
204          * Check for NaN
205          */
206         if (strcmp(str, "NaN") == 0)
207                 PG_RETURN_NUMERIC(make_result(&const_nan));
208
209         /*
210          * Use set_var_from_str() to parse the input string and return it in
211          * the packed DB storage format
212          */
213         init_var(&value);
214         set_var_from_str(str, &value);
215
216         apply_typmod(&value, typmod);
217
218         res = make_result(&value);
219         free_var(&value);
220
221         PG_RETURN_NUMERIC(res);
222 }
223
224
225 /* ----------
226  * numeric_out() -
227  *
228  *      Output function for numeric data type
229  * ----------
230  */
231 Datum
232 numeric_out(PG_FUNCTION_ARGS)
233 {
234         Numeric         num = PG_GETARG_NUMERIC(0);
235         NumericVar      x;
236         char       *str;
237
238         /*
239          * Handle NaN
240          */
241         if (NUMERIC_IS_NAN(num))
242                 PG_RETURN_CSTRING(pstrdup("NaN"));
243
244         /*
245          * Get the number in the variable format.
246          *
247          * Even if we didn't need to change format, we'd still need to copy the
248          * value to have a modifiable copy for rounding.  set_var_from_num()
249          * also guarantees there is extra digit space in case we produce a
250          * carry out from rounding.
251          */
252         init_var(&x);
253         set_var_from_num(num, &x);
254
255         str = get_str_from_var(&x, x.dscale);
256
257         free_var(&x);
258
259         PG_RETURN_CSTRING(str);
260 }
261
262
263 /* ----------
264  * numeric() -
265  *
266  *      This is a special function called by the Postgres database system
267  *      before a value is stored in a tuples attribute. The precision and
268  *      scale of the attribute have to be applied on the value.
269  * ----------
270  */
271 Datum
272 numeric(PG_FUNCTION_ARGS)
273 {
274         Numeric         num = PG_GETARG_NUMERIC(0);
275         int32           typmod = PG_GETARG_INT32(1);
276         Numeric         new;
277         int32           tmp_typmod;
278         int                     precision;
279         int                     scale;
280         int                     maxweight;
281         NumericVar      var;
282
283         /*
284          * Handle NaN
285          */
286         if (NUMERIC_IS_NAN(num))
287                 PG_RETURN_NUMERIC(make_result(&const_nan));
288
289         /*
290          * If the value isn't a valid type modifier, simply return a copy of
291          * the input value
292          */
293         if (typmod < (int32) (VARHDRSZ))
294         {
295                 new = (Numeric) palloc(num->varlen);
296                 memcpy(new, num, num->varlen);
297                 PG_RETURN_NUMERIC(new);
298         }
299
300         /*
301          * Get the precision and scale out of the typmod value
302          */
303         tmp_typmod = typmod - VARHDRSZ;
304         precision = (tmp_typmod >> 16) & 0xffff;
305         scale = tmp_typmod & 0xffff;
306         maxweight = precision - scale;
307
308         /*
309          * If the number is in bounds and due to the present result scale no
310          * rounding could be necessary, just make a copy of the input and
311          * modify its scale fields.
312          */
313         if (num->n_weight < maxweight && scale >= num->n_rscale)
314         {
315                 new = (Numeric) palloc(num->varlen);
316                 memcpy(new, num, num->varlen);
317                 new->n_rscale = scale;
318                 new->n_sign_dscale = NUMERIC_SIGN(new) |
319                         ((uint16) scale & NUMERIC_DSCALE_MASK);
320                 PG_RETURN_NUMERIC(new);
321         }
322
323         /*
324          * We really need to fiddle with things - unpack the number into a
325          * variable and let apply_typmod() do it.
326          */
327         init_var(&var);
328
329         set_var_from_num(num, &var);
330         apply_typmod(&var, typmod);
331         new = make_result(&var);
332
333         free_var(&var);
334
335         PG_RETURN_NUMERIC(new);
336 }
337
338
339 /* ----------------------------------------------------------------------
340  *
341  * Sign manipulation, rounding and the like
342  *
343  * ----------------------------------------------------------------------
344  */
345
346 Datum
347 numeric_abs(PG_FUNCTION_ARGS)
348 {
349         Numeric         num = PG_GETARG_NUMERIC(0);
350         Numeric         res;
351
352         /*
353          * Handle NaN
354          */
355         if (NUMERIC_IS_NAN(num))
356                 PG_RETURN_NUMERIC(make_result(&const_nan));
357
358         /*
359          * Do it the easy way directly on the packed format
360          */
361         res = (Numeric) palloc(num->varlen);
362         memcpy(res, num, num->varlen);
363
364         res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
365
366         PG_RETURN_NUMERIC(res);
367 }
368
369
370 Datum
371 numeric_uminus(PG_FUNCTION_ARGS)
372 {
373         Numeric         num = PG_GETARG_NUMERIC(0);
374         Numeric         res;
375
376         /*
377          * Handle NaN
378          */
379         if (NUMERIC_IS_NAN(num))
380                 PG_RETURN_NUMERIC(make_result(&const_nan));
381
382         /*
383          * Do it the easy way directly on the packed format
384          */
385         res = (Numeric) palloc(num->varlen);
386         memcpy(res, num, num->varlen);
387
388         /*
389          * The packed format is known to be totally zero digit trimmed always.
390          * So we can identify a ZERO by the fact that there are no digits at
391          * all.  Do nothing to a zero.
392          */
393         if (num->varlen != NUMERIC_HDRSZ)
394         {
395                 /* Else, flip the sign */
396                 if (NUMERIC_SIGN(num) == NUMERIC_POS)
397                         res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num);
398                 else
399                         res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
400         }
401
402         PG_RETURN_NUMERIC(res);
403 }
404
405
406 Datum
407 numeric_uplus(PG_FUNCTION_ARGS)
408 {
409         Numeric         num = PG_GETARG_NUMERIC(0);
410         Numeric         res;
411
412         res = (Numeric) palloc(num->varlen);
413         memcpy(res, num, num->varlen);
414
415         PG_RETURN_NUMERIC(res);
416 }
417
418
419 Datum
420 numeric_sign(PG_FUNCTION_ARGS)
421 {
422         Numeric         num = PG_GETARG_NUMERIC(0);
423         Numeric         res;
424         NumericVar      result;
425
426         /*
427          * Handle NaN
428          */
429         if (NUMERIC_IS_NAN(num))
430                 PG_RETURN_NUMERIC(make_result(&const_nan));
431
432         init_var(&result);
433
434         /*
435          * The packed format is known to be totally zero digit trimmed always.
436          * So we can identify a ZERO by the fact that there are no digits at
437          * all.
438          */
439         if (num->varlen == NUMERIC_HDRSZ)
440                 set_var_from_var(&const_zero, &result);
441         else
442         {
443
444                 /*
445                  * And if there are some, we return a copy of ONE with the sign of
446                  * our argument
447                  */
448                 set_var_from_var(&const_one, &result);
449                 result.sign = NUMERIC_SIGN(num);
450         }
451
452         res = make_result(&result);
453         free_var(&result);
454
455         PG_RETURN_NUMERIC(res);
456 }
457
458
459 /* ----------
460  * numeric_round() -
461  *
462  *      Round a value to have 'scale' digits after the decimal point.
463  *      We allow negative 'scale', implying rounding before the decimal
464  *      point --- Oracle interprets rounding that way.
465  * ----------
466  */
467 Datum
468 numeric_round(PG_FUNCTION_ARGS)
469 {
470         Numeric         num = PG_GETARG_NUMERIC(0);
471         int32           scale = PG_GETARG_INT32(1);
472         Numeric         res;
473         NumericVar      arg;
474         int                     i;
475
476         /*
477          * Handle NaN
478          */
479         if (NUMERIC_IS_NAN(num))
480                 PG_RETURN_NUMERIC(make_result(&const_nan));
481
482         /*
483          * Limit the scale value to avoid possible overflow in calculations
484          * below.
485          */
486         scale = MIN(NUMERIC_MAX_RESULT_SCALE,
487                                 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
488
489         /*
490          * Unpack the argument and round it at the proper digit position
491          */
492         init_var(&arg);
493         set_var_from_num(num, &arg);
494
495         i = arg.weight + scale + 1;
496
497         if (i < arg.ndigits)
498         {
499
500                 /*
501                  * If i = 0, the value loses all digits, but could round up if its
502                  * first digit is more than 4.  If i < 0 the result must be 0.
503                  */
504                 if (i < 0)
505                         arg.ndigits = 0;
506                 else
507                 {
508                         int                     carry = (arg.digits[i] > 4) ? 1 : 0;
509
510                         arg.ndigits = i;
511
512                         while (carry)
513                         {
514                                 carry += arg.digits[--i];
515                                 arg.digits[i] = carry % 10;
516                                 carry /= 10;
517                         }
518
519                         if (i < 0)
520                         {
521                                 Assert(i == -1);/* better not have added more than 1 digit */
522                                 Assert(arg.digits > arg.buf);
523                                 arg.digits--;
524                                 arg.ndigits++;
525                                 arg.weight++;
526                         }
527                 }
528         }
529
530         /*
531          * Set result's scale to something reasonable.
532          */
533         scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
534         arg.rscale = scale;
535         arg.dscale = scale;
536
537         /*
538          * Return the rounded result
539          */
540         res = make_result(&arg);
541
542         free_var(&arg);
543         PG_RETURN_NUMERIC(res);
544 }
545
546
547 /* ----------
548  * numeric_trunc() -
549  *
550  *      Truncate a value to have 'scale' digits after the decimal point.
551  *      We allow negative 'scale', implying a truncation before the decimal
552  *      point --- Oracle interprets truncation that way.
553  * ----------
554  */
555 Datum
556 numeric_trunc(PG_FUNCTION_ARGS)
557 {
558         Numeric         num = PG_GETARG_NUMERIC(0);
559         int32           scale = PG_GETARG_INT32(1);
560         Numeric         res;
561         NumericVar      arg;
562
563         /*
564          * Handle NaN
565          */
566         if (NUMERIC_IS_NAN(num))
567                 PG_RETURN_NUMERIC(make_result(&const_nan));
568
569         /*
570          * Limit the scale value to avoid possible overflow in calculations
571          * below.
572          */
573         scale = MIN(NUMERIC_MAX_RESULT_SCALE,
574                                 MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
575
576         /*
577          * Unpack the argument and truncate it at the proper digit position
578          */
579         init_var(&arg);
580         set_var_from_num(num, &arg);
581
582         arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));
583
584         /*
585          * Set result's scale to something reasonable.
586          */
587         scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
588         arg.rscale = scale;
589         arg.dscale = scale;
590
591         /*
592          * Return the truncated result
593          */
594         res = make_result(&arg);
595
596         free_var(&arg);
597         PG_RETURN_NUMERIC(res);
598 }
599
600
601 /* ----------
602  * numeric_ceil() -
603  *
604  *      Return the smallest integer greater than or equal to the argument
605  * ----------
606  */
607 Datum
608 numeric_ceil(PG_FUNCTION_ARGS)
609 {
610         Numeric         num = PG_GETARG_NUMERIC(0);
611         Numeric         res;
612         NumericVar      result;
613
614         if (NUMERIC_IS_NAN(num))
615                 PG_RETURN_NUMERIC(make_result(&const_nan));
616
617         init_var(&result);
618
619         set_var_from_num(num, &result);
620         ceil_var(&result, &result);
621
622         result.dscale = 0;
623
624         res = make_result(&result);
625         free_var(&result);
626
627         PG_RETURN_NUMERIC(res);
628 }
629
630
631 /* ----------
632  * numeric_floor() -
633  *
634  *      Return the largest integer equal to or less than the argument
635  * ----------
636  */
637 Datum
638 numeric_floor(PG_FUNCTION_ARGS)
639 {
640         Numeric         num = PG_GETARG_NUMERIC(0);
641         Numeric         res;
642         NumericVar      result;
643
644         if (NUMERIC_IS_NAN(num))
645                 PG_RETURN_NUMERIC(make_result(&const_nan));
646
647         init_var(&result);
648
649         set_var_from_num(num, &result);
650         floor_var(&result, &result);
651
652         result.dscale = 0;
653
654         res = make_result(&result);
655         free_var(&result);
656
657         PG_RETURN_NUMERIC(res);
658 }
659
660
661 /* ----------------------------------------------------------------------
662  *
663  * Comparison functions
664  *
665  * Note: btree indexes need these routines not to leak memory; therefore,
666  * be careful to free working copies of toasted datums.  Most places don't
667  * need to be so careful.
668  * ----------------------------------------------------------------------
669  */
670
671
672 Datum
673 numeric_cmp(PG_FUNCTION_ARGS)
674 {
675         Numeric         num1 = PG_GETARG_NUMERIC(0);
676         Numeric         num2 = PG_GETARG_NUMERIC(1);
677         int                     result;
678
679         result = cmp_numerics(num1, num2);
680
681         PG_FREE_IF_COPY(num1, 0);
682         PG_FREE_IF_COPY(num2, 1);
683
684         PG_RETURN_INT32(result);
685 }
686
687
688 Datum
689 numeric_eq(PG_FUNCTION_ARGS)
690 {
691         Numeric         num1 = PG_GETARG_NUMERIC(0);
692         Numeric         num2 = PG_GETARG_NUMERIC(1);
693         bool            result;
694
695         result = cmp_numerics(num1, num2) == 0;
696
697         PG_FREE_IF_COPY(num1, 0);
698         PG_FREE_IF_COPY(num2, 1);
699
700         PG_RETURN_BOOL(result);
701 }
702
703 Datum
704 numeric_ne(PG_FUNCTION_ARGS)
705 {
706         Numeric         num1 = PG_GETARG_NUMERIC(0);
707         Numeric         num2 = PG_GETARG_NUMERIC(1);
708         bool            result;
709
710         result = cmp_numerics(num1, num2) != 0;
711
712         PG_FREE_IF_COPY(num1, 0);
713         PG_FREE_IF_COPY(num2, 1);
714
715         PG_RETURN_BOOL(result);
716 }
717
718 Datum
719 numeric_gt(PG_FUNCTION_ARGS)
720 {
721         Numeric         num1 = PG_GETARG_NUMERIC(0);
722         Numeric         num2 = PG_GETARG_NUMERIC(1);
723         bool            result;
724
725         result = cmp_numerics(num1, num2) > 0;
726
727         PG_FREE_IF_COPY(num1, 0);
728         PG_FREE_IF_COPY(num2, 1);
729
730         PG_RETURN_BOOL(result);
731 }
732
733 Datum
734 numeric_ge(PG_FUNCTION_ARGS)
735 {
736         Numeric         num1 = PG_GETARG_NUMERIC(0);
737         Numeric         num2 = PG_GETARG_NUMERIC(1);
738         bool            result;
739
740         result = cmp_numerics(num1, num2) >= 0;
741
742         PG_FREE_IF_COPY(num1, 0);
743         PG_FREE_IF_COPY(num2, 1);
744
745         PG_RETURN_BOOL(result);
746 }
747
748 Datum
749 numeric_lt(PG_FUNCTION_ARGS)
750 {
751         Numeric         num1 = PG_GETARG_NUMERIC(0);
752         Numeric         num2 = PG_GETARG_NUMERIC(1);
753         bool            result;
754
755         result = cmp_numerics(num1, num2) < 0;
756
757         PG_FREE_IF_COPY(num1, 0);
758         PG_FREE_IF_COPY(num2, 1);
759
760         PG_RETURN_BOOL(result);
761 }
762
763 Datum
764 numeric_le(PG_FUNCTION_ARGS)
765 {
766         Numeric         num1 = PG_GETARG_NUMERIC(0);
767         Numeric         num2 = PG_GETARG_NUMERIC(1);
768         bool            result;
769
770         result = cmp_numerics(num1, num2) <= 0;
771
772         PG_FREE_IF_COPY(num1, 0);
773         PG_FREE_IF_COPY(num2, 1);
774
775         PG_RETURN_BOOL(result);
776 }
777
778 static int
779 cmp_numerics(Numeric num1, Numeric num2)
780 {
781         int                     result;
782
783         /*
784          * We consider all NANs to be equal and larger than any non-NAN.
785          * This is somewhat arbitrary; the important thing is to have a
786          * consistent sort order.
787          */
788         if (NUMERIC_IS_NAN(num1))
789         {
790                 if (NUMERIC_IS_NAN(num2))
791                         result = 0;                     /* NAN = NAN */
792                 else
793                         result = 1;                     /* NAN > non-NAN */
794         }
795         else if (NUMERIC_IS_NAN(num2))
796         {
797                 result = -1;                    /* non-NAN < NAN */
798         }
799         else
800         {
801                 NumericVar      arg1;
802                 NumericVar      arg2;
803
804                 init_var(&arg1);
805                 init_var(&arg2);
806
807                 set_var_from_num(num1, &arg1);
808                 set_var_from_num(num2, &arg2);
809
810                 result = cmp_var(&arg1, &arg2);
811
812                 free_var(&arg1);
813                 free_var(&arg2);
814         }
815
816         return result;
817 }
818
819
820 /* ----------------------------------------------------------------------
821  *
822  * Arithmetic base functions
823  *
824  * ----------------------------------------------------------------------
825  */
826
827
828 /* ----------
829  * numeric_add() -
830  *
831  *      Add two numerics
832  * ----------
833  */
834 Datum
835 numeric_add(PG_FUNCTION_ARGS)
836 {
837         Numeric         num1 = PG_GETARG_NUMERIC(0);
838         Numeric         num2 = PG_GETARG_NUMERIC(1);
839         NumericVar      arg1;
840         NumericVar      arg2;
841         NumericVar      result;
842         Numeric         res;
843
844         /*
845          * Handle NaN
846          */
847         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
848                 PG_RETURN_NUMERIC(make_result(&const_nan));
849
850         /*
851          * Unpack the values, let add_var() compute the result and return it.
852          * The internals of add_var() will automatically set the correct
853          * result and display scales in the result.
854          */
855         init_var(&arg1);
856         init_var(&arg2);
857         init_var(&result);
858
859         set_var_from_num(num1, &arg1);
860         set_var_from_num(num2, &arg2);
861
862         add_var(&arg1, &arg2, &result);
863         res = make_result(&result);
864
865         free_var(&arg1);
866         free_var(&arg2);
867         free_var(&result);
868
869         PG_RETURN_NUMERIC(res);
870 }
871
872
873 /* ----------
874  * numeric_sub() -
875  *
876  *      Subtract one numeric from another
877  * ----------
878  */
879 Datum
880 numeric_sub(PG_FUNCTION_ARGS)
881 {
882         Numeric         num1 = PG_GETARG_NUMERIC(0);
883         Numeric         num2 = PG_GETARG_NUMERIC(1);
884         NumericVar      arg1;
885         NumericVar      arg2;
886         NumericVar      result;
887         Numeric         res;
888
889         /*
890          * Handle NaN
891          */
892         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
893                 PG_RETURN_NUMERIC(make_result(&const_nan));
894
895         /*
896          * Unpack the two arguments, let sub_var() compute the result and
897          * return it.
898          */
899         init_var(&arg1);
900         init_var(&arg2);
901         init_var(&result);
902
903         set_var_from_num(num1, &arg1);
904         set_var_from_num(num2, &arg2);
905
906         sub_var(&arg1, &arg2, &result);
907         res = make_result(&result);
908
909         free_var(&arg1);
910         free_var(&arg2);
911         free_var(&result);
912
913         PG_RETURN_NUMERIC(res);
914 }
915
916
917 /* ----------
918  * numeric_mul() -
919  *
920  *      Calculate the product of two numerics
921  * ----------
922  */
923 Datum
924 numeric_mul(PG_FUNCTION_ARGS)
925 {
926         Numeric         num1 = PG_GETARG_NUMERIC(0);
927         Numeric         num2 = PG_GETARG_NUMERIC(1);
928         NumericVar      arg1;
929         NumericVar      arg2;
930         NumericVar      result;
931         Numeric         res;
932
933         /*
934          * Handle NaN
935          */
936         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
937                 PG_RETURN_NUMERIC(make_result(&const_nan));
938
939         /*
940          * Unpack the arguments, let mul_var() compute the result and return
941          * it. Unlike add_var() and sub_var(), mul_var() will round the result
942          * to the scale stored in global_rscale. In the case of numeric_mul(),
943          * which is invoked for the * operator on numerics, we set it to the
944          * exact representation for the product (rscale = sum(rscale of arg1,
945          * rscale of arg2) and the same for the dscale).
946          */
947         init_var(&arg1);
948         init_var(&arg2);
949         init_var(&result);
950
951         set_var_from_num(num1, &arg1);
952         set_var_from_num(num2, &arg2);
953
954         global_rscale = arg1.rscale + arg2.rscale;
955
956         mul_var(&arg1, &arg2, &result);
957
958         result.dscale = arg1.dscale + arg2.dscale;
959
960         res = make_result(&result);
961
962         free_var(&arg1);
963         free_var(&arg2);
964         free_var(&result);
965
966         PG_RETURN_NUMERIC(res);
967 }
968
969
970 /* ----------
971  * numeric_div() -
972  *
973  *      Divide one numeric into another
974  * ----------
975  */
976 Datum
977 numeric_div(PG_FUNCTION_ARGS)
978 {
979         Numeric         num1 = PG_GETARG_NUMERIC(0);
980         Numeric         num2 = PG_GETARG_NUMERIC(1);
981         NumericVar      arg1;
982         NumericVar      arg2;
983         NumericVar      result;
984         Numeric         res;
985         int                     res_dscale;
986
987         /*
988          * Handle NaN
989          */
990         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
991                 PG_RETURN_NUMERIC(make_result(&const_nan));
992
993         /*
994          * Unpack the arguments
995          */
996         init_var(&arg1);
997         init_var(&arg2);
998         init_var(&result);
999
1000         set_var_from_num(num1, &arg1);
1001         set_var_from_num(num2, &arg2);
1002
1003         /* ----------
1004          * The result scale of a division isn't specified in any
1005          * SQL standard. For Postgres it is the following (where
1006          * SR, DR are the result- and display-scales of the returned
1007          * value, S1, D1, S2 and D2 are the scales of the two arguments,
1008          * The minimum and maximum scales are compile time options from
1009          * numeric.h):
1010          *
1011          *      DR = MIN(MAX(D1 + D2, MIN_DISPLAY_SCALE), MAX_DISPLAY_SCALE)
1012          *      SR = MIN(MAX(MAX(S1 + S2, MIN_RESULT_SCALE), DR + 4), MAX_RESULT_SCALE)
1013          *
1014          * By default, any result is computed with a minimum of 34 digits
1015          * after the decimal point or at least with 4 digits more than
1016          * displayed.
1017          * ----------
1018          */
1019         res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1020         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1021         global_rscale = MAX(arg1.rscale + arg2.rscale,
1022                                                 NUMERIC_MIN_RESULT_SCALE);
1023         global_rscale = MAX(global_rscale, res_dscale + 4);
1024         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1025
1026         /*
1027          * Do the divide, set the display scale and return the result
1028          */
1029         div_var(&arg1, &arg2, &result);
1030
1031         result.dscale = res_dscale;
1032
1033         res = make_result(&result);
1034
1035         free_var(&arg1);
1036         free_var(&arg2);
1037         free_var(&result);
1038
1039         PG_RETURN_NUMERIC(res);
1040 }
1041
1042
1043 /* ----------
1044  * numeric_mod() -
1045  *
1046  *      Calculate the modulo of two numerics
1047  * ----------
1048  */
1049 Datum
1050 numeric_mod(PG_FUNCTION_ARGS)
1051 {
1052         Numeric         num1 = PG_GETARG_NUMERIC(0);
1053         Numeric         num2 = PG_GETARG_NUMERIC(1);
1054         Numeric         res;
1055         NumericVar      arg1;
1056         NumericVar      arg2;
1057         NumericVar      result;
1058
1059         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1060                 PG_RETURN_NUMERIC(make_result(&const_nan));
1061
1062         init_var(&arg1);
1063         init_var(&arg2);
1064         init_var(&result);
1065
1066         set_var_from_num(num1, &arg1);
1067         set_var_from_num(num2, &arg2);
1068
1069         mod_var(&arg1, &arg2, &result);
1070
1071         res = make_result(&result);
1072
1073         free_var(&result);
1074         free_var(&arg2);
1075         free_var(&arg1);
1076
1077         PG_RETURN_NUMERIC(res);
1078 }
1079
1080
1081 /* ----------
1082  * numeric_inc() -
1083  *
1084  *      Increment a number by one
1085  * ----------
1086  */
1087 Datum
1088 numeric_inc(PG_FUNCTION_ARGS)
1089 {
1090         Numeric         num = PG_GETARG_NUMERIC(0);
1091         NumericVar      arg;
1092         Numeric         res;
1093
1094         /*
1095          * Handle NaN
1096          */
1097         if (NUMERIC_IS_NAN(num))
1098                 PG_RETURN_NUMERIC(make_result(&const_nan));
1099
1100         /*
1101          * Compute the result and return it
1102          */
1103         init_var(&arg);
1104
1105         set_var_from_num(num, &arg);
1106
1107         add_var(&arg, &const_one, &arg);
1108         res = make_result(&arg);
1109
1110         free_var(&arg);
1111
1112         PG_RETURN_NUMERIC(res);
1113 }
1114
1115
1116 /* ----------
1117  * numeric_smaller() -
1118  *
1119  *      Return the smaller of two numbers
1120  * ----------
1121  */
1122 Datum
1123 numeric_smaller(PG_FUNCTION_ARGS)
1124 {
1125         Numeric         num1 = PG_GETARG_NUMERIC(0);
1126         Numeric         num2 = PG_GETARG_NUMERIC(1);
1127         NumericVar      arg1;
1128         NumericVar      arg2;
1129         Numeric         res;
1130
1131         /*
1132          * Handle NaN
1133          */
1134         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1135                 PG_RETURN_NUMERIC(make_result(&const_nan));
1136
1137         /*
1138          * Unpack the values, and decide which is the smaller one
1139          */
1140         init_var(&arg1);
1141         init_var(&arg2);
1142
1143         set_var_from_num(num1, &arg1);
1144         set_var_from_num(num2, &arg2);
1145
1146         if (cmp_var(&arg1, &arg2) <= 0)
1147                 res = make_result(&arg1);
1148         else
1149                 res = make_result(&arg2);
1150
1151         free_var(&arg1);
1152         free_var(&arg2);
1153
1154         PG_RETURN_NUMERIC(res);
1155 }
1156
1157
1158 /* ----------
1159  * numeric_larger() -
1160  *
1161  *      Return the larger of two numbers
1162  * ----------
1163  */
1164 Datum
1165 numeric_larger(PG_FUNCTION_ARGS)
1166 {
1167         Numeric         num1 = PG_GETARG_NUMERIC(0);
1168         Numeric         num2 = PG_GETARG_NUMERIC(1);
1169         NumericVar      arg1;
1170         NumericVar      arg2;
1171         Numeric         res;
1172
1173         /*
1174          * Handle NaN
1175          */
1176         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1177                 PG_RETURN_NUMERIC(make_result(&const_nan));
1178
1179         /*
1180          * Unpack the values, and decide which is the larger one
1181          */
1182         init_var(&arg1);
1183         init_var(&arg2);
1184
1185         set_var_from_num(num1, &arg1);
1186         set_var_from_num(num2, &arg2);
1187
1188         if (cmp_var(&arg1, &arg2) >= 0)
1189                 res = make_result(&arg1);
1190         else
1191                 res = make_result(&arg2);
1192
1193         free_var(&arg1);
1194         free_var(&arg2);
1195
1196         PG_RETURN_NUMERIC(res);
1197 }
1198
1199
1200 /* ----------------------------------------------------------------------
1201  *
1202  * Complex math functions
1203  *
1204  * ----------------------------------------------------------------------
1205  */
1206
1207
1208 /* ----------
1209  * numeric_sqrt() -
1210  *
1211  *      Compute the square root of a numeric.
1212  * ----------
1213  */
1214 Datum
1215 numeric_sqrt(PG_FUNCTION_ARGS)
1216 {
1217         Numeric         num = PG_GETARG_NUMERIC(0);
1218         Numeric         res;
1219         NumericVar      arg;
1220         NumericVar      result;
1221         int                     res_dscale;
1222
1223         /*
1224          * Handle NaN
1225          */
1226         if (NUMERIC_IS_NAN(num))
1227                 PG_RETURN_NUMERIC(make_result(&const_nan));
1228
1229         /*
1230          * Unpack the argument, determine the scales like for divide, let
1231          * sqrt_var() do the calculation and return the result.
1232          */
1233         init_var(&arg);
1234         init_var(&result);
1235
1236         set_var_from_num(num, &arg);
1237
1238         res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1239         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1240         global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1241         global_rscale = MAX(global_rscale, res_dscale + 4);
1242         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1243
1244         sqrt_var(&arg, &result);
1245
1246         result.dscale = res_dscale;
1247
1248         res = make_result(&result);
1249
1250         free_var(&result);
1251         free_var(&arg);
1252
1253         PG_RETURN_NUMERIC(res);
1254 }
1255
1256
1257 /* ----------
1258  * numeric_exp() -
1259  *
1260  *      Raise e to the power of x
1261  * ----------
1262  */
1263 Datum
1264 numeric_exp(PG_FUNCTION_ARGS)
1265 {
1266         Numeric         num = PG_GETARG_NUMERIC(0);
1267         Numeric         res;
1268         NumericVar      arg;
1269         NumericVar      result;
1270         int                     res_dscale;
1271
1272         /*
1273          * Handle NaN
1274          */
1275         if (NUMERIC_IS_NAN(num))
1276                 PG_RETURN_NUMERIC(make_result(&const_nan));
1277
1278         /*
1279          * Same procedure like for sqrt().
1280          */
1281         init_var(&arg);
1282         init_var(&result);
1283         set_var_from_num(num, &arg);
1284
1285         res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1286         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1287         global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1288         global_rscale = MAX(global_rscale, res_dscale + 4);
1289         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1290
1291         exp_var(&arg, &result);
1292
1293         result.dscale = res_dscale;
1294
1295         res = make_result(&result);
1296
1297         free_var(&result);
1298         free_var(&arg);
1299
1300         PG_RETURN_NUMERIC(res);
1301 }
1302
1303
1304 /* ----------
1305  * numeric_ln() -
1306  *
1307  *      Compute the natural logarithm of x
1308  * ----------
1309  */
1310 Datum
1311 numeric_ln(PG_FUNCTION_ARGS)
1312 {
1313         Numeric         num = PG_GETARG_NUMERIC(0);
1314         Numeric         res;
1315         NumericVar      arg;
1316         NumericVar      result;
1317         int                     res_dscale;
1318
1319         /*
1320          * Handle NaN
1321          */
1322         if (NUMERIC_IS_NAN(num))
1323                 PG_RETURN_NUMERIC(make_result(&const_nan));
1324
1325         /*
1326          * Same procedure like for sqrt()
1327          */
1328         init_var(&arg);
1329         init_var(&result);
1330         set_var_from_num(num, &arg);
1331
1332         res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1333         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1334         global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE);
1335         global_rscale = MAX(global_rscale, res_dscale + 4);
1336         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1337
1338         ln_var(&arg, &result);
1339
1340         result.dscale = res_dscale;
1341
1342         res = make_result(&result);
1343
1344         free_var(&result);
1345         free_var(&arg);
1346
1347         PG_RETURN_NUMERIC(res);
1348 }
1349
1350
1351 /* ----------
1352  * numeric_log() -
1353  *
1354  *      Compute the logarithm of x in a given base
1355  * ----------
1356  */
1357 Datum
1358 numeric_log(PG_FUNCTION_ARGS)
1359 {
1360         Numeric         num1 = PG_GETARG_NUMERIC(0);
1361         Numeric         num2 = PG_GETARG_NUMERIC(1);
1362         Numeric         res;
1363         NumericVar      arg1;
1364         NumericVar      arg2;
1365         NumericVar      result;
1366         int                     res_dscale;
1367
1368         /*
1369          * Handle NaN
1370          */
1371         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1372                 PG_RETURN_NUMERIC(make_result(&const_nan));
1373
1374         /*
1375          * Initialize things and calculate scales
1376          */
1377         init_var(&arg1);
1378         init_var(&arg2);
1379         init_var(&result);
1380         set_var_from_num(num1, &arg1);
1381         set_var_from_num(num2, &arg2);
1382
1383         res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1384         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1385         global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1386         global_rscale = MAX(global_rscale, res_dscale + 4);
1387         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1388
1389         /*
1390          * Call log_var() to compute and return the result
1391          */
1392         log_var(&arg1, &arg2, &result);
1393
1394         result.dscale = res_dscale;
1395
1396         res = make_result(&result);
1397
1398         free_var(&result);
1399         free_var(&arg2);
1400         free_var(&arg1);
1401
1402         PG_RETURN_NUMERIC(res);
1403 }
1404
1405
1406 /* ----------
1407  * numeric_power() -
1408  *
1409  *      Raise m to the power of x
1410  * ----------
1411  */
1412 Datum
1413 numeric_power(PG_FUNCTION_ARGS)
1414 {
1415         Numeric         num1 = PG_GETARG_NUMERIC(0);
1416         Numeric         num2 = PG_GETARG_NUMERIC(1);
1417         Numeric         res;
1418         NumericVar      arg1;
1419         NumericVar      arg2;
1420         NumericVar      result;
1421         int                     res_dscale;
1422
1423         /*
1424          * Handle NaN
1425          */
1426         if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
1427                 PG_RETURN_NUMERIC(make_result(&const_nan));
1428
1429         /*
1430          * Initialize things and calculate scales
1431          */
1432         init_var(&arg1);
1433         init_var(&arg2);
1434         init_var(&result);
1435         set_var_from_num(num1, &arg1);
1436         set_var_from_num(num2, &arg2);
1437
1438         res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE);
1439         res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1440         global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE);
1441         global_rscale = MAX(global_rscale, res_dscale + 4);
1442         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
1443
1444         /*
1445          * Call log_var() to compute and return the result
1446          */
1447         power_var(&arg1, &arg2, &result);
1448
1449         result.dscale = res_dscale;
1450
1451         res = make_result(&result);
1452
1453         free_var(&result);
1454         free_var(&arg2);
1455         free_var(&arg1);
1456
1457         PG_RETURN_NUMERIC(res);
1458 }
1459
1460
1461 /* ----------------------------------------------------------------------
1462  *
1463  * Type conversion functions
1464  *
1465  * ----------------------------------------------------------------------
1466  */
1467
1468
1469 Datum
1470 int4_numeric(PG_FUNCTION_ARGS)
1471 {
1472         int32           val = PG_GETARG_INT32(0);
1473         Numeric         res;
1474         NumericVar      result;
1475         char       *tmp;
1476
1477         init_var(&result);
1478
1479         tmp = DatumGetCString(DirectFunctionCall1(int4out,
1480                                                                                           Int32GetDatum(val)));
1481         set_var_from_str(tmp, &result);
1482         res = make_result(&result);
1483
1484         free_var(&result);
1485         pfree(tmp);
1486
1487         PG_RETURN_NUMERIC(res);
1488 }
1489
1490
1491 Datum
1492 numeric_int4(PG_FUNCTION_ARGS)
1493 {
1494         Numeric         num = PG_GETARG_NUMERIC(0);
1495         NumericVar      x;
1496         char       *str;
1497         Datum           result;
1498
1499         /* XXX would it be better to return NULL? */
1500         if (NUMERIC_IS_NAN(num))
1501                 elog(ERROR, "Cannot convert NaN to int4");
1502
1503         /*
1504          * Get the number in the variable format so we can round to integer.
1505          */
1506         init_var(&x);
1507         set_var_from_num(num, &x);
1508
1509         str = get_str_from_var(&x, 0);          /* dscale = 0 produces rounding */
1510
1511         free_var(&x);
1512
1513         result = DirectFunctionCall1(int4in, CStringGetDatum(str));
1514         pfree(str);
1515
1516         PG_RETURN_DATUM(result);
1517 }
1518
1519
1520 Datum
1521 int8_numeric(PG_FUNCTION_ARGS)
1522 {
1523         Datum           val = PG_GETARG_DATUM(0);
1524         Numeric         res;
1525         NumericVar      result;
1526         char       *tmp;
1527
1528         init_var(&result);
1529
1530         tmp = DatumGetCString(DirectFunctionCall1(int8out, val));
1531         set_var_from_str(tmp, &result);
1532         res = make_result(&result);
1533
1534         free_var(&result);
1535         pfree(tmp);
1536
1537         PG_RETURN_NUMERIC(res);
1538 }
1539
1540
1541 Datum
1542 numeric_int8(PG_FUNCTION_ARGS)
1543 {
1544         Numeric         num = PG_GETARG_NUMERIC(0);
1545         NumericVar      x;
1546         char       *str;
1547         Datum           result;
1548
1549         /* XXX would it be better to return NULL? */
1550         if (NUMERIC_IS_NAN(num))
1551                 elog(ERROR, "Cannot convert NaN to int8");
1552
1553         /*
1554          * Get the number in the variable format so we can round to integer.
1555          */
1556         init_var(&x);
1557         set_var_from_num(num, &x);
1558
1559         str = get_str_from_var(&x, 0);          /* dscale = 0 produces rounding */
1560
1561         free_var(&x);
1562
1563         result = DirectFunctionCall1(int8in, CStringGetDatum(str));
1564         pfree(str);
1565
1566         PG_RETURN_DATUM(result);
1567 }
1568
1569
1570 Datum
1571 int2_numeric(PG_FUNCTION_ARGS)
1572 {
1573         int16           val = PG_GETARG_INT16(0);
1574         Numeric         res;
1575         NumericVar      result;
1576         char       *tmp;
1577
1578         init_var(&result);
1579
1580         tmp = DatumGetCString(DirectFunctionCall1(int2out,
1581                                                                                           Int16GetDatum(val)));
1582         set_var_from_str(tmp, &result);
1583         res = make_result(&result);
1584
1585         free_var(&result);
1586         pfree(tmp);
1587
1588         PG_RETURN_NUMERIC(res);
1589 }
1590
1591
1592 Datum
1593 numeric_int2(PG_FUNCTION_ARGS)
1594 {
1595         Numeric         num = PG_GETARG_NUMERIC(0);
1596         NumericVar      x;
1597         char       *str;
1598         Datum           result;
1599
1600         /* XXX would it be better to return NULL? */
1601         if (NUMERIC_IS_NAN(num))
1602                 elog(ERROR, "Cannot convert NaN to int2");
1603
1604         /*
1605          * Get the number in the variable format so we can round to integer.
1606          */
1607         init_var(&x);
1608         set_var_from_num(num, &x);
1609
1610         str = get_str_from_var(&x, 0);          /* dscale = 0 produces rounding */
1611
1612         free_var(&x);
1613
1614         result = DirectFunctionCall1(int2in, CStringGetDatum(str));
1615         pfree(str);
1616
1617         return result;
1618 }
1619
1620
1621 Datum
1622 float8_numeric(PG_FUNCTION_ARGS)
1623 {
1624         float8          val = PG_GETARG_FLOAT8(0);
1625         Numeric         res;
1626         NumericVar      result;
1627         char            buf[DBL_DIG + 100];
1628
1629         if (isnan(val))
1630                 PG_RETURN_NUMERIC(make_result(&const_nan));
1631
1632         sprintf(buf, "%.*g", DBL_DIG, val);
1633
1634         init_var(&result);
1635
1636         set_var_from_str(buf, &result);
1637         res = make_result(&result);
1638
1639         free_var(&result);
1640
1641         PG_RETURN_NUMERIC(res);
1642 }
1643
1644
1645 Datum
1646 numeric_float8(PG_FUNCTION_ARGS)
1647 {
1648         Numeric         num = PG_GETARG_NUMERIC(0);
1649         char       *tmp;
1650         Datum           result;
1651
1652         if (NUMERIC_IS_NAN(num))
1653                 PG_RETURN_FLOAT8(NAN);
1654
1655         tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
1656                                                                                           NumericGetDatum(num)));
1657
1658         result = DirectFunctionCall1(float8in, CStringGetDatum(tmp));
1659
1660         pfree(tmp);
1661
1662         PG_RETURN_DATUM(result);
1663 }
1664
1665
1666 /* Convert numeric to float8; if out of range, return +/- HUGE_VAL */
1667 Datum
1668 numeric_float8_no_overflow(PG_FUNCTION_ARGS)
1669 {
1670         Numeric         num = PG_GETARG_NUMERIC(0);
1671         char       *tmp;
1672         double          val;
1673         char       *endptr;
1674
1675         if (NUMERIC_IS_NAN(num))
1676                 PG_RETURN_FLOAT8(NAN);
1677
1678         tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
1679                                                                                           NumericGetDatum(num)));
1680
1681         /* unlike float8in, we ignore ERANGE from strtod */
1682         val = strtod(tmp, &endptr);
1683         if (*endptr != '\0')
1684         {
1685                 /* shouldn't happen ... */
1686                 elog(ERROR, "Bad float8 input format '%s'", tmp);
1687         }
1688
1689         pfree(tmp);
1690
1691         PG_RETURN_FLOAT8(val);
1692 }
1693
1694
1695 Datum
1696 float4_numeric(PG_FUNCTION_ARGS)
1697 {
1698         float4          val = PG_GETARG_FLOAT4(0);
1699         Numeric         res;
1700         NumericVar      result;
1701         char            buf[FLT_DIG + 100];
1702
1703         if (isnan(val))
1704                 PG_RETURN_NUMERIC(make_result(&const_nan));
1705
1706         sprintf(buf, "%.*g", FLT_DIG, val);
1707
1708         init_var(&result);
1709
1710         set_var_from_str(buf, &result);
1711         res = make_result(&result);
1712
1713         free_var(&result);
1714
1715         PG_RETURN_NUMERIC(res);
1716 }
1717
1718
1719 Datum
1720 numeric_float4(PG_FUNCTION_ARGS)
1721 {
1722         Numeric         num = PG_GETARG_NUMERIC(0);
1723         char       *tmp;
1724         Datum           result;
1725
1726         if (NUMERIC_IS_NAN(num))
1727                 PG_RETURN_FLOAT4((float4) NAN);
1728
1729         tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
1730                                                                                           NumericGetDatum(num)));
1731
1732         result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));
1733
1734         pfree(tmp);
1735
1736         PG_RETURN_DATUM(result);
1737 }
1738
1739
1740 /* ----------------------------------------------------------------------
1741  *
1742  * Aggregate functions
1743  *
1744  * The transition datatype for all these aggregates is a 3-element array
1745  * of Numeric, holding the values N, sum(X), sum(X*X) in that order.
1746  *
1747  * We represent N as a numeric mainly to avoid having to build a special
1748  * datatype; it's unlikely it'd overflow an int4, but ...
1749  *
1750  * ----------------------------------------------------------------------
1751  */
1752
1753 static ArrayType *
1754 do_numeric_accum(ArrayType *transarray, Numeric newval)
1755 {
1756         Datum      *transdatums;
1757         int                     ndatums;
1758         Datum           N,
1759                                 sumX,
1760                                 sumX2;
1761         ArrayType  *result;
1762
1763         /* We assume the input is array of numeric */
1764         deconstruct_array(transarray,
1765                                           false, -1, 'i',
1766                                           &transdatums, &ndatums);
1767         if (ndatums != 3)
1768                 elog(ERROR, "do_numeric_accum: expected 3-element numeric array");
1769         N = transdatums[0];
1770         sumX = transdatums[1];
1771         sumX2 = transdatums[2];
1772
1773         N = DirectFunctionCall1(numeric_inc, N);
1774         sumX = DirectFunctionCall2(numeric_add, sumX,
1775                                                            NumericGetDatum(newval));
1776         sumX2 = DirectFunctionCall2(numeric_add, sumX2,
1777                                                                 DirectFunctionCall2(numeric_mul,
1778                                                                                                  NumericGetDatum(newval),
1779                                                                                            NumericGetDatum(newval)));
1780
1781         transdatums[0] = N;
1782         transdatums[1] = sumX;
1783         transdatums[2] = sumX2;
1784
1785         result = construct_array(transdatums, 3,
1786                                                          false, -1, 'i');
1787
1788         return result;
1789 }
1790
1791 Datum
1792 numeric_accum(PG_FUNCTION_ARGS)
1793 {
1794         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1795         Numeric         newval = PG_GETARG_NUMERIC(1);
1796
1797         PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1798 }
1799
1800 /*
1801  * Integer data types all use Numeric accumulators to share code and
1802  * avoid risk of overflow.  For int2 and int4 inputs, Numeric accumulation
1803  * is overkill for the N and sum(X) values, but definitely not overkill
1804  * for the sum(X*X) value.  Hence, we use int2_accum and int4_accum only
1805  * for stddev/variance --- there are faster special-purpose accumulator
1806  * routines for SUM and AVG of these datatypes.
1807  */
1808
1809 Datum
1810 int2_accum(PG_FUNCTION_ARGS)
1811 {
1812         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1813         Datum           newval2 = PG_GETARG_DATUM(1);
1814         Numeric         newval;
1815
1816         newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
1817
1818         PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1819 }
1820
1821 Datum
1822 int4_accum(PG_FUNCTION_ARGS)
1823 {
1824         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1825         Datum           newval4 = PG_GETARG_DATUM(1);
1826         Numeric         newval;
1827
1828         newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
1829
1830         PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1831 }
1832
1833 Datum
1834 int8_accum(PG_FUNCTION_ARGS)
1835 {
1836         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1837         Datum           newval8 = PG_GETARG_DATUM(1);
1838         Numeric         newval;
1839
1840         newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
1841
1842         PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
1843 }
1844
1845 Datum
1846 numeric_avg(PG_FUNCTION_ARGS)
1847 {
1848         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1849         Datum      *transdatums;
1850         int                     ndatums;
1851         Numeric         N,
1852                                 sumX;
1853
1854         /* We assume the input is array of numeric */
1855         deconstruct_array(transarray,
1856                                           false, -1, 'i',
1857                                           &transdatums, &ndatums);
1858         if (ndatums != 3)
1859                 elog(ERROR, "numeric_avg: expected 3-element numeric array");
1860         N = DatumGetNumeric(transdatums[0]);
1861         sumX = DatumGetNumeric(transdatums[1]);
1862         /* ignore sumX2 */
1863
1864         /* SQL92 defines AVG of no values to be NULL */
1865         /* N is zero iff no digits (cf. numeric_uminus) */
1866         if (N->varlen == NUMERIC_HDRSZ)
1867                 PG_RETURN_NULL();
1868
1869         PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
1870                                                                                 NumericGetDatum(sumX),
1871                                                                                 NumericGetDatum(N)));
1872 }
1873
1874 Datum
1875 numeric_variance(PG_FUNCTION_ARGS)
1876 {
1877         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1878         Datum      *transdatums;
1879         int                     ndatums;
1880         Numeric         N,
1881                                 sumX,
1882                                 sumX2,
1883                                 res;
1884         NumericVar      vN,
1885                                 vsumX,
1886                                 vsumX2,
1887                                 vNminus1;
1888
1889         /* We assume the input is array of numeric */
1890         deconstruct_array(transarray,
1891                                           false, -1, 'i',
1892                                           &transdatums, &ndatums);
1893         if (ndatums != 3)
1894                 elog(ERROR, "numeric_variance: expected 3-element numeric array");
1895         N = DatumGetNumeric(transdatums[0]);
1896         sumX = DatumGetNumeric(transdatums[1]);
1897         sumX2 = DatumGetNumeric(transdatums[2]);
1898
1899         if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
1900                 PG_RETURN_NUMERIC(make_result(&const_nan));
1901
1902         /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
1903         /* N is zero iff no digits (cf. numeric_uminus) */
1904         if (N->varlen == NUMERIC_HDRSZ)
1905                 PG_RETURN_NULL();
1906
1907         init_var(&vN);
1908         set_var_from_num(N, &vN);
1909
1910         init_var(&vNminus1);
1911         sub_var(&vN, &const_one, &vNminus1);
1912
1913         if (cmp_var(&vNminus1, &const_zero) <= 0)
1914         {
1915                 free_var(&vN);
1916                 free_var(&vNminus1);
1917                 PG_RETURN_NUMERIC(make_result(&const_zero));
1918         }
1919
1920         init_var(&vsumX);
1921         set_var_from_num(sumX, &vsumX);
1922         init_var(&vsumX2);
1923         set_var_from_num(sumX2, &vsumX2);
1924
1925         mul_var(&vsumX, &vsumX, &vsumX);        /* now vsumX contains sumX * sumX */
1926         mul_var(&vN, &vsumX2, &vsumX2);         /* now vsumX2 contains N * sumX2 */
1927         sub_var(&vsumX2, &vsumX, &vsumX2);      /* N * sumX2 - sumX * sumX */
1928         mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
1929         div_var(&vsumX2, &vNminus1, &vsumX);            /* variance */
1930
1931         res = make_result(&vsumX);
1932
1933         free_var(&vN);
1934         free_var(&vNminus1);
1935         free_var(&vsumX);
1936         free_var(&vsumX2);
1937
1938         PG_RETURN_NUMERIC(res);
1939 }
1940
1941 Datum
1942 numeric_stddev(PG_FUNCTION_ARGS)
1943 {
1944         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1945         Datum      *transdatums;
1946         int                     ndatums;
1947         Numeric         N,
1948                                 sumX,
1949                                 sumX2,
1950                                 res;
1951         NumericVar      vN,
1952                                 vsumX,
1953                                 vsumX2,
1954                                 vNminus1;
1955
1956         /* We assume the input is array of numeric */
1957         deconstruct_array(transarray,
1958                                           false, -1, 'i',
1959                                           &transdatums, &ndatums);
1960         if (ndatums != 3)
1961                 elog(ERROR, "numeric_stddev: expected 3-element numeric array");
1962         N = DatumGetNumeric(transdatums[0]);
1963         sumX = DatumGetNumeric(transdatums[1]);
1964         sumX2 = DatumGetNumeric(transdatums[2]);
1965
1966         if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
1967                 PG_RETURN_NUMERIC(make_result(&const_nan));
1968
1969         /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
1970         /* N is zero iff no digits (cf. numeric_uminus) */
1971         if (N->varlen == NUMERIC_HDRSZ)
1972                 PG_RETURN_NULL();
1973
1974         init_var(&vN);
1975         set_var_from_num(N, &vN);
1976
1977         init_var(&vNminus1);
1978         sub_var(&vN, &const_one, &vNminus1);
1979
1980         if (cmp_var(&vNminus1, &const_zero) <= 0)
1981         {
1982                 free_var(&vN);
1983                 free_var(&vNminus1);
1984                 PG_RETURN_NUMERIC(make_result(&const_zero));
1985         }
1986
1987         init_var(&vsumX);
1988         set_var_from_num(sumX, &vsumX);
1989         init_var(&vsumX2);
1990         set_var_from_num(sumX2, &vsumX2);
1991
1992         mul_var(&vsumX, &vsumX, &vsumX);        /* now vsumX contains sumX * sumX */
1993         mul_var(&vN, &vsumX2, &vsumX2);         /* now vsumX2 contains N * sumX2 */
1994         sub_var(&vsumX2, &vsumX, &vsumX2);      /* N * sumX2 - sumX * sumX */
1995         mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
1996         div_var(&vsumX2, &vNminus1, &vsumX);            /* variance */
1997         sqrt_var(&vsumX, &vsumX);       /* stddev */
1998
1999         res = make_result(&vsumX);
2000
2001         free_var(&vN);
2002         free_var(&vNminus1);
2003         free_var(&vsumX);
2004         free_var(&vsumX2);
2005
2006         PG_RETURN_NUMERIC(res);
2007 }
2008
2009
2010 /*
2011  * SUM transition functions for integer datatypes.
2012  *
2013  * To avoid overflow, we use accumulators wider than the input datatype.
2014  * A Numeric accumulator is needed for int8 input; for int4 and int2
2015  * inputs, we use int8 accumulators which should be sufficient for practical
2016  * purposes.  (The latter two therefore don't really belong in this file,
2017  * but we keep them here anyway.)
2018  *
2019  * Because SQL92 defines the SUM() of no values to be NULL, not zero,
2020  * the initial condition of the transition data value needs to be NULL. This
2021  * means we can't rely on ExecAgg to automatically insert the first non-null
2022  * data value into the transition data: it doesn't know how to do the type
2023  * conversion.  The upshot is that these routines have to be marked non-strict
2024  * and handle substitution of the first non-null input themselves.
2025  */
2026
2027 Datum
2028 int2_sum(PG_FUNCTION_ARGS)
2029 {
2030         int64           oldsum;
2031         int64           newval;
2032
2033         if (PG_ARGISNULL(0))
2034         {
2035                 /* No non-null input seen so far... */
2036                 if (PG_ARGISNULL(1))
2037                         PG_RETURN_NULL();       /* still no non-null */
2038                 /* This is the first non-null input. */
2039                 newval = (int64) PG_GETARG_INT16(1);
2040                 PG_RETURN_INT64(newval);
2041         }
2042
2043         oldsum = PG_GETARG_INT64(0);
2044
2045         /* Leave sum unchanged if new input is null. */
2046         if (PG_ARGISNULL(1))
2047                 PG_RETURN_INT64(oldsum);
2048
2049         /* OK to do the addition. */
2050         newval = oldsum + (int64) PG_GETARG_INT16(1);
2051
2052         PG_RETURN_INT64(newval);
2053 }
2054
2055 Datum
2056 int4_sum(PG_FUNCTION_ARGS)
2057 {
2058         int64           oldsum;
2059         int64           newval;
2060
2061         if (PG_ARGISNULL(0))
2062         {
2063                 /* No non-null input seen so far... */
2064                 if (PG_ARGISNULL(1))
2065                         PG_RETURN_NULL();       /* still no non-null */
2066                 /* This is the first non-null input. */
2067                 newval = (int64) PG_GETARG_INT32(1);
2068                 PG_RETURN_INT64(newval);
2069         }
2070
2071         oldsum = PG_GETARG_INT64(0);
2072
2073         /* Leave sum unchanged if new input is null. */
2074         if (PG_ARGISNULL(1))
2075                 PG_RETURN_INT64(oldsum);
2076
2077         /* OK to do the addition. */
2078         newval = oldsum + (int64) PG_GETARG_INT32(1);
2079
2080         PG_RETURN_INT64(newval);
2081 }
2082
2083 Datum
2084 int8_sum(PG_FUNCTION_ARGS)
2085 {
2086         Numeric         oldsum;
2087         Datum           newval;
2088
2089         if (PG_ARGISNULL(0))
2090         {
2091                 /* No non-null input seen so far... */
2092                 if (PG_ARGISNULL(1))
2093                         PG_RETURN_NULL();       /* still no non-null */
2094                 /* This is the first non-null input. */
2095                 newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
2096                 PG_RETURN_DATUM(newval);
2097         }
2098
2099         oldsum = PG_GETARG_NUMERIC(0);
2100
2101         /* Leave sum unchanged if new input is null. */
2102         if (PG_ARGISNULL(1))
2103                 PG_RETURN_NUMERIC(oldsum);
2104
2105         /* OK to do the addition. */
2106         newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
2107
2108         PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
2109                                                                                 NumericGetDatum(oldsum), newval));
2110 }
2111
2112
2113 /*
2114  * Routines for avg(int2) and avg(int4).  The transition datatype
2115  * is a two-element int8 array, holding count and sum.
2116  */
2117
2118 typedef struct Int8TransTypeData
2119 {
2120 #ifndef INT64_IS_BUSTED
2121         int64           count;
2122         int64           sum;
2123 #else
2124         /* "int64" isn't really 64 bits, so fake up properly-aligned fields */
2125         int32           count;
2126         int32           pad1;
2127         int32           sum;
2128         int32           pad2;
2129 #endif
2130 } Int8TransTypeData;
2131
2132 Datum
2133 int2_avg_accum(PG_FUNCTION_ARGS)
2134 {
2135         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
2136         int16           newval = PG_GETARG_INT16(1);
2137         Int8TransTypeData *transdata;
2138
2139         /*
2140          * We copied the input array, so it's okay to scribble on it directly.
2141          */
2142         if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
2143                 elog(ERROR, "int2_avg_accum: expected 2-element int8 array");
2144         transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
2145
2146         transdata->count++;
2147         transdata->sum += newval;
2148
2149         PG_RETURN_ARRAYTYPE_P(transarray);
2150 }
2151
2152 Datum
2153 int4_avg_accum(PG_FUNCTION_ARGS)
2154 {
2155         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
2156         int32           newval = PG_GETARG_INT32(1);
2157         Int8TransTypeData *transdata;
2158
2159         /*
2160          * We copied the input array, so it's okay to scribble on it directly.
2161          */
2162         if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
2163                 elog(ERROR, "int4_avg_accum: expected 2-element int8 array");
2164         transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
2165
2166         transdata->count++;
2167         transdata->sum += newval;
2168
2169         PG_RETURN_ARRAYTYPE_P(transarray);
2170 }
2171
2172 Datum
2173 int8_avg(PG_FUNCTION_ARGS)
2174 {
2175         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
2176         Int8TransTypeData *transdata;
2177         Datum           countd,
2178                                 sumd;
2179
2180         if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
2181                 elog(ERROR, "int8_avg: expected 2-element int8 array");
2182         transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
2183
2184         /* SQL92 defines AVG of no values to be NULL */
2185         if (transdata->count == 0)
2186                 PG_RETURN_NULL();
2187
2188         countd = DirectFunctionCall1(int8_numeric,
2189                                                                  Int64GetDatumFast(transdata->count));
2190         sumd = DirectFunctionCall1(int8_numeric,
2191                                                            Int64GetDatumFast(transdata->sum));
2192
2193         PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
2194 }
2195
2196
2197 /* ----------------------------------------------------------------------
2198  *
2199  * Local functions follow
2200  *
2201  * ----------------------------------------------------------------------
2202  */
2203
2204
2205 #ifdef NUMERIC_DEBUG
2206
2207 /* ----------
2208  * dump_numeric() - Dump a value in the db storage format for debugging
2209  * ----------
2210  */
2211 static void
2212 dump_numeric(char *str, Numeric num)
2213 {
2214         int                     i;
2215
2216         printf("%s: NUMERIC w=%d r=%d d=%d ", str, num->n_weight, num->n_rscale,
2217                    NUMERIC_DSCALE(num));
2218         switch (NUMERIC_SIGN(num))
2219         {
2220                 case NUMERIC_POS:
2221                         printf("POS");
2222                         break;
2223                 case NUMERIC_NEG:
2224                         printf("NEG");
2225                         break;
2226                 case NUMERIC_NAN:
2227                         printf("NaN");
2228                         break;
2229                 default:
2230                         printf("SIGN=0x%x", NUMERIC_SIGN(num));
2231                         break;
2232         }
2233
2234         for (i = 0; i < num->varlen - NUMERIC_HDRSZ; i++)
2235                 printf(" %d %d", (num->n_data[i] >> 4) & 0x0f, num->n_data[i] & 0x0f);
2236         printf("\n");
2237 }
2238
2239
2240 /* ----------
2241  * dump_var() - Dump a value in the variable format for debugging
2242  * ----------
2243  */
2244 static void
2245 dump_var(char *str, NumericVar *var)
2246 {
2247         int                     i;
2248
2249         printf("%s: VAR w=%d r=%d d=%d ", str, var->weight, var->rscale,
2250                    var->dscale);
2251         switch (var->sign)
2252         {
2253                 case NUMERIC_POS:
2254                         printf("POS");
2255                         break;
2256                 case NUMERIC_NEG:
2257                         printf("NEG");
2258                         break;
2259                 case NUMERIC_NAN:
2260                         printf("NaN");
2261                         break;
2262                 default:
2263                         printf("SIGN=0x%x", var->sign);
2264                         break;
2265         }
2266
2267         for (i = 0; i < var->ndigits; i++)
2268                 printf(" %d", var->digits[i]);
2269
2270         printf("\n");
2271 }
2272
2273 #endif   /* NUMERIC_DEBUG */
2274
2275
2276 /* ----------
2277  * alloc_var() -
2278  *
2279  *      Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
2280  * ----------
2281  */
2282 static void
2283 alloc_var(NumericVar *var, int ndigits)
2284 {
2285         digitbuf_free(var->buf);
2286         var->buf = digitbuf_alloc(ndigits + 1);
2287         var->buf[0] = 0;
2288         var->digits = var->buf + 1;
2289         var->ndigits = ndigits;
2290 }
2291
2292
2293 /* ----------
2294  * free_var() -
2295  *
2296  *      Return the digit buffer of a variable to the free pool
2297  * ----------
2298  */
2299 static void
2300 free_var(NumericVar *var)
2301 {
2302         digitbuf_free(var->buf);
2303         var->buf = NULL;
2304         var->digits = NULL;
2305         var->sign = NUMERIC_NAN;
2306 }
2307
2308
2309 /* ----------
2310  * zero_var() -
2311  *
2312  *      Set a variable to ZERO.
2313  *      Note: rscale and dscale are not touched.
2314  * ----------
2315  */
2316 static void
2317 zero_var(NumericVar *var)
2318 {
2319         digitbuf_free(var->buf);
2320         var->buf = NULL;
2321         var->digits = NULL;
2322         var->ndigits = 0;
2323         var->weight = 0;                        /* by convention; doesn't really matter */
2324         var->sign = NUMERIC_POS;        /* anything but NAN... */
2325 }
2326
2327
2328 /* ----------
2329  * set_var_from_str()
2330  *
2331  *      Parse a string and put the number into a variable
2332  * ----------
2333  */
2334 static void
2335 set_var_from_str(char *str, NumericVar *dest)
2336 {
2337         char       *cp = str;
2338         bool            have_dp = FALSE;
2339         int                     i = 0;
2340
2341         while (*cp)
2342         {
2343                 if (!isspace((unsigned char) *cp))
2344                         break;
2345                 cp++;
2346         }
2347
2348         alloc_var(dest, strlen(cp));
2349         dest->weight = -1;
2350         dest->dscale = 0;
2351         dest->sign = NUMERIC_POS;
2352
2353         switch (*cp)
2354         {
2355                 case '+':
2356                         dest->sign = NUMERIC_POS;
2357                         cp++;
2358                         break;
2359
2360                 case '-':
2361                         dest->sign = NUMERIC_NEG;
2362                         cp++;
2363                         break;
2364         }
2365
2366         if (*cp == '.')
2367         {
2368                 have_dp = TRUE;
2369                 cp++;
2370         }
2371
2372         if (!isdigit((unsigned char) *cp))
2373                 elog(ERROR, "Bad numeric input format '%s'", str);
2374
2375         while (*cp)
2376         {
2377                 if (isdigit((unsigned char) *cp))
2378                 {
2379                         dest->digits[i++] = *cp++ - '0';
2380                         if (!have_dp)
2381                                 dest->weight++;
2382                         else
2383                                 dest->dscale++;
2384                 }
2385                 else if (*cp == '.')
2386                 {
2387                         if (have_dp)
2388                                 elog(ERROR, "Bad numeric input format '%s'", str);
2389                         have_dp = TRUE;
2390                         cp++;
2391                 }
2392                 else
2393                         break;
2394         }
2395         dest->ndigits = i;
2396
2397         /* Handle exponent, if any */
2398         if (*cp == 'e' || *cp == 'E')
2399         {
2400                 long            exponent;
2401                 char       *endptr;
2402
2403                 cp++;
2404                 exponent = strtol(cp, &endptr, 10);
2405                 if (endptr == cp)
2406                         elog(ERROR, "Bad numeric input format '%s'", str);
2407                 cp = endptr;
2408                 if (exponent > NUMERIC_MAX_PRECISION ||
2409                         exponent < -NUMERIC_MAX_PRECISION)
2410                         elog(ERROR, "Bad numeric input format '%s'", str);
2411                 dest->weight += (int) exponent;
2412                 dest->dscale -= (int) exponent;
2413                 if (dest->dscale < 0)
2414                         dest->dscale = 0;
2415         }
2416
2417         /* Should be nothing left but spaces */
2418         while (*cp)
2419         {
2420                 if (!isspace((unsigned char) *cp))
2421                         elog(ERROR, "Bad numeric input format '%s'", str);
2422                 cp++;
2423         }
2424
2425         /* Strip any leading zeroes */
2426         while (dest->ndigits > 0 && *(dest->digits) == 0)
2427         {
2428                 (dest->digits)++;
2429                 (dest->weight)--;
2430                 (dest->ndigits)--;
2431         }
2432         if (dest->ndigits == 0)
2433                 dest->weight = 0;
2434
2435         dest->rscale = dest->dscale;
2436 }
2437
2438
2439 /*
2440  * set_var_from_num() -
2441  *
2442  *      Parse back the packed db format into a variable
2443  *
2444  */
2445 static void
2446 set_var_from_num(Numeric num, NumericVar *dest)
2447 {
2448         NumericDigit *digit;
2449         int                     i;
2450         int                     n;
2451
2452         n = num->varlen - NUMERIC_HDRSZ;        /* number of digit-pairs in packed
2453                                                                                  * fmt */
2454
2455         alloc_var(dest, n * 2);
2456
2457         dest->weight = num->n_weight;
2458         dest->rscale = num->n_rscale;
2459         dest->dscale = NUMERIC_DSCALE(num);
2460         dest->sign = NUMERIC_SIGN(num);
2461
2462         digit = dest->digits;
2463
2464         for (i = 0; i < n; i++)
2465         {
2466                 unsigned char digitpair = num->n_data[i];
2467
2468                 *digit++ = (digitpair >> 4) & 0x0f;
2469                 *digit++ = digitpair & 0x0f;
2470         }
2471 }
2472
2473
2474 /* ----------
2475  * set_var_from_var() -
2476  *
2477  *      Copy one variable into another
2478  * ----------
2479  */
2480 static void
2481 set_var_from_var(NumericVar *value, NumericVar *dest)
2482 {
2483         NumericDigit *newbuf;
2484
2485         newbuf = digitbuf_alloc(value->ndigits + 1);
2486         newbuf[0] = 0;                          /* spare digit for rounding */
2487         memcpy(newbuf + 1, value->digits, value->ndigits);
2488
2489         digitbuf_free(dest->buf);
2490
2491         memcpy(dest, value, sizeof(NumericVar));
2492         dest->buf = newbuf;
2493         dest->digits = newbuf + 1;
2494 }
2495
2496
2497 /* ----------
2498  * get_str_from_var() -
2499  *
2500  *      Convert a var to text representation (guts of numeric_out).
2501  *      CAUTION: var's contents may be modified by rounding!
2502  *      Caller must have checked for NaN case.
2503  *      Returns a palloc'd string.
2504  * ----------
2505  */
2506 static char *
2507 get_str_from_var(NumericVar *var, int dscale)
2508 {
2509         char       *str;
2510         char       *cp;
2511         int                     i;
2512         int                     d;
2513
2514         /*
2515          * Check if we must round up before printing the value and do so.
2516          */
2517         i = dscale + var->weight + 1;
2518         if (i >= 0 && var->ndigits > i)
2519         {
2520                 int                     carry = (var->digits[i] > 4) ? 1 : 0;
2521
2522                 var->ndigits = i;
2523
2524                 while (carry)
2525                 {
2526                         carry += var->digits[--i];
2527                         var->digits[i] = carry % 10;
2528                         carry /= 10;
2529                 }
2530
2531                 if (i < 0)
2532                 {
2533                         Assert(i == -1);        /* better not have added more than 1 digit */
2534                         Assert(var->digits > var->buf);
2535                         var->digits--;
2536                         var->ndigits++;
2537                         var->weight++;
2538                 }
2539         }
2540         else
2541                 var->ndigits = MAX(0, MIN(i, var->ndigits));
2542
2543         /*
2544          * Allocate space for the result
2545          */
2546         str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4);
2547         cp = str;
2548
2549         /*
2550          * Output a dash for negative values
2551          */
2552         if (var->sign == NUMERIC_NEG)
2553                 *cp++ = '-';
2554
2555         /*
2556          * Output all digits before the decimal point
2557          */
2558         i = MAX(var->weight, 0);
2559         d = 0;
2560
2561         while (i >= 0)
2562         {
2563                 if (i <= var->weight && d < var->ndigits)
2564                         *cp++ = var->digits[d++] + '0';
2565                 else
2566                         *cp++ = '0';
2567                 i--;
2568         }
2569
2570         /*
2571          * If requested, output a decimal point and all the digits that follow
2572          * it.
2573          */
2574         if (dscale > 0)
2575         {
2576                 *cp++ = '.';
2577                 while (i >= -dscale)
2578                 {
2579                         if (i <= var->weight && d < var->ndigits)
2580                                 *cp++ = var->digits[d++] + '0';
2581                         else
2582                                 *cp++ = '0';
2583                         i--;
2584                 }
2585         }
2586
2587         /*
2588          * terminate the string and return it
2589          */
2590         *cp = '\0';
2591         return str;
2592 }
2593
2594
2595 /* ----------
2596  * make_result() -
2597  *
2598  *      Create the packed db numeric format in palloc()'d memory from
2599  *      a variable.  The var's rscale determines the number of digits kept.
2600  * ----------
2601  */
2602 static Numeric
2603 make_result(NumericVar *var)
2604 {
2605         Numeric         result;
2606         NumericDigit *digit = var->digits;
2607         int                     weight = var->weight;
2608         int                     sign = var->sign;
2609         int                     n;
2610         int                     i,
2611                                 j;
2612
2613         if (sign == NUMERIC_NAN)
2614         {
2615                 result = (Numeric) palloc(NUMERIC_HDRSZ);
2616
2617                 result->varlen = NUMERIC_HDRSZ;
2618                 result->n_weight = 0;
2619                 result->n_rscale = 0;
2620                 result->n_sign_dscale = NUMERIC_NAN;
2621
2622                 dump_numeric("make_result()", result);
2623                 return result;
2624         }
2625
2626         n = MAX(0, MIN(var->ndigits, var->weight + var->rscale + 1));
2627
2628         /* truncate leading zeroes */
2629         while (n > 0 && *digit == 0)
2630         {
2631                 digit++;
2632                 weight--;
2633                 n--;
2634         }
2635         /* truncate trailing zeroes */
2636         while (n > 0 && digit[n - 1] == 0)
2637                 n--;
2638
2639         /* If zero result, force to weight=0 and positive sign */
2640         if (n == 0)
2641         {
2642                 weight = 0;
2643                 sign = NUMERIC_POS;
2644         }
2645
2646         result = (Numeric) palloc(NUMERIC_HDRSZ + (n + 1) / 2);
2647         result->varlen = NUMERIC_HDRSZ + (n + 1) / 2;
2648         result->n_weight = weight;
2649         result->n_rscale = var->rscale;
2650         result->n_sign_dscale = sign |
2651                 ((uint16) var->dscale & NUMERIC_DSCALE_MASK);
2652
2653         i = 0;
2654         j = 0;
2655         while (j < n)
2656         {
2657                 unsigned char digitpair = digit[j++] << 4;
2658
2659                 if (j < n)
2660                         digitpair |= digit[j++];
2661                 result->n_data[i++] = digitpair;
2662         }
2663
2664         dump_numeric("make_result()", result);
2665         return result;
2666 }
2667
2668
2669 /* ----------
2670  * apply_typmod() -
2671  *
2672  *      Do bounds checking and rounding according to the attributes
2673  *      typmod field.
2674  * ----------
2675  */
2676 static void
2677 apply_typmod(NumericVar *var, int32 typmod)
2678 {
2679         int                     precision;
2680         int                     scale;
2681         int                     maxweight;
2682         int                     i;
2683
2684         /* Do nothing if we have a default typmod (-1) */
2685         if (typmod < (int32) (VARHDRSZ))
2686                 return;
2687
2688         typmod -= VARHDRSZ;
2689         precision = (typmod >> 16) & 0xffff;
2690         scale = typmod & 0xffff;
2691         maxweight = precision - scale;
2692
2693         /* Round to target scale */
2694         i = scale + var->weight + 1;
2695         if (i >= 0 && var->ndigits > i)
2696         {
2697                 int                     carry = (var->digits[i] > 4) ? 1 : 0;
2698
2699                 var->ndigits = i;
2700
2701                 while (carry)
2702                 {
2703                         carry += var->digits[--i];
2704                         var->digits[i] = carry % 10;
2705                         carry /= 10;
2706                 }
2707
2708                 if (i < 0)
2709                 {
2710                         Assert(i == -1);        /* better not have added more than 1 digit */
2711                         Assert(var->digits > var->buf);
2712                         var->digits--;
2713                         var->ndigits++;
2714                         var->weight++;
2715                 }
2716         }
2717         else
2718                 var->ndigits = MAX(0, MIN(i, var->ndigits));
2719
2720         /*
2721          * Check for overflow - note we can't do this before rounding, because
2722          * rounding could raise the weight.  Also note that the var's weight
2723          * could be inflated by leading zeroes, which will be stripped before
2724          * storage but perhaps might not have been yet. In any case, we must
2725          * recognize a true zero, whose weight doesn't mean anything.
2726          */
2727         if (var->weight >= maxweight)
2728         {
2729                 /* Determine true weight; and check for all-zero result */
2730                 int                     tweight = var->weight;
2731
2732                 for (i = 0; i < var->ndigits; i++)
2733                 {
2734                         if (var->digits[i])
2735                                 break;
2736                         tweight--;
2737                 }
2738
2739                 if (tweight >= maxweight && i < var->ndigits)
2740                         elog(ERROR, "overflow on numeric "
2741                           "ABS(value) >= 10^%d for field with precision %d scale %d",
2742                                  tweight, precision, scale);
2743         }
2744
2745         var->rscale = scale;
2746         var->dscale = scale;
2747 }
2748
2749
2750 /* ----------
2751  * cmp_var() -
2752  *
2753  *      Compare two values on variable level
2754  * ----------
2755  */
2756 static int
2757 cmp_var(NumericVar *var1, NumericVar *var2)
2758 {
2759         if (var1->ndigits == 0)
2760         {
2761                 if (var2->ndigits == 0)
2762                         return 0;
2763                 if (var2->sign == NUMERIC_NEG)
2764                         return 1;
2765                 return -1;
2766         }
2767         if (var2->ndigits == 0)
2768         {
2769                 if (var1->sign == NUMERIC_POS)
2770                         return 1;
2771                 return -1;
2772         }
2773
2774         if (var1->sign == NUMERIC_POS)
2775         {
2776                 if (var2->sign == NUMERIC_NEG)
2777                         return 1;
2778                 return cmp_abs(var1, var2);
2779         }
2780
2781         if (var2->sign == NUMERIC_POS)
2782                 return -1;
2783
2784         return cmp_abs(var2, var1);
2785 }
2786
2787
2788 /* ----------
2789  * add_var() -
2790  *
2791  *      Full version of add functionality on variable level (handling signs).
2792  *      result might point to one of the operands too without danger.
2793  * ----------
2794  */
2795 static void
2796 add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
2797 {
2798
2799         /*
2800          * Decide on the signs of the two variables what to do
2801          */
2802         if (var1->sign == NUMERIC_POS)
2803         {
2804                 if (var2->sign == NUMERIC_POS)
2805                 {
2806
2807                         /*
2808                          * Both are positive result = +(ABS(var1) + ABS(var2))
2809                          */
2810                         add_abs(var1, var2, result);
2811                         result->sign = NUMERIC_POS;
2812                 }
2813                 else
2814                 {
2815
2816                         /*
2817                          * var1 is positive, var2 is negative Must compare absolute
2818                          * values
2819                          */
2820                         switch (cmp_abs(var1, var2))
2821                         {
2822                                 case 0:
2823                                         /* ----------
2824                                          * ABS(var1) == ABS(var2)
2825                                          * result = ZERO
2826                                          * ----------
2827                                          */
2828                                         zero_var(result);
2829                                         result->rscale = MAX(var1->rscale, var2->rscale);
2830                                         result->dscale = MAX(var1->dscale, var2->dscale);
2831                                         break;
2832
2833                                 case 1:
2834                                         /* ----------
2835                                          * ABS(var1) > ABS(var2)
2836                                          * result = +(ABS(var1) - ABS(var2))
2837                                          * ----------
2838                                          */
2839                                         sub_abs(var1, var2, result);
2840                                         result->sign = NUMERIC_POS;
2841                                         break;
2842
2843                                 case -1:
2844                                         /* ----------
2845                                          * ABS(var1) < ABS(var2)
2846                                          * result = -(ABS(var2) - ABS(var1))
2847                                          * ----------
2848                                          */
2849                                         sub_abs(var2, var1, result);
2850                                         result->sign = NUMERIC_NEG;
2851                                         break;
2852                         }
2853                 }
2854         }
2855         else
2856         {
2857                 if (var2->sign == NUMERIC_POS)
2858                 {
2859                         /* ----------
2860                          * var1 is negative, var2 is positive
2861                          * Must compare absolute values
2862                          * ----------
2863                          */
2864                         switch (cmp_abs(var1, var2))
2865                         {
2866                                 case 0:
2867                                         /* ----------
2868                                          * ABS(var1) == ABS(var2)
2869                                          * result = ZERO
2870                                          * ----------
2871                                          */
2872                                         zero_var(result);
2873                                         result->rscale = MAX(var1->rscale, var2->rscale);
2874                                         result->dscale = MAX(var1->dscale, var2->dscale);
2875                                         break;
2876
2877                                 case 1:
2878                                         /* ----------
2879                                          * ABS(var1) > ABS(var2)
2880                                          * result = -(ABS(var1) - ABS(var2))
2881                                          * ----------
2882                                          */
2883                                         sub_abs(var1, var2, result);
2884                                         result->sign = NUMERIC_NEG;
2885                                         break;
2886
2887                                 case -1:
2888                                         /* ----------
2889                                          * ABS(var1) < ABS(var2)
2890                                          * result = +(ABS(var2) - ABS(var1))
2891                                          * ----------
2892                                          */
2893                                         sub_abs(var2, var1, result);
2894                                         result->sign = NUMERIC_POS;
2895                                         break;
2896                         }
2897                 }
2898                 else
2899                 {
2900                         /* ----------
2901                          * Both are negative
2902                          * result = -(ABS(var1) + ABS(var2))
2903                          * ----------
2904                          */
2905                         add_abs(var1, var2, result);
2906                         result->sign = NUMERIC_NEG;
2907                 }
2908         }
2909 }
2910
2911
2912 /* ----------
2913  * sub_var() -
2914  *
2915  *      Full version of sub functionality on variable level (handling signs).
2916  *      result might point to one of the operands too without danger.
2917  * ----------
2918  */
2919 static void
2920 sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
2921 {
2922
2923         /*
2924          * Decide on the signs of the two variables what to do
2925          */
2926         if (var1->sign == NUMERIC_POS)
2927         {
2928                 if (var2->sign == NUMERIC_NEG)
2929                 {
2930                         /* ----------
2931                          * var1 is positive, var2 is negative
2932                          * result = +(ABS(var1) + ABS(var2))
2933                          * ----------
2934                          */
2935                         add_abs(var1, var2, result);
2936                         result->sign = NUMERIC_POS;
2937                 }
2938                 else
2939                 {
2940                         /* ----------
2941                          * Both are positive
2942                          * Must compare absolute values
2943                          * ----------
2944                          */
2945                         switch (cmp_abs(var1, var2))
2946                         {
2947                                 case 0:
2948                                         /* ----------
2949                                          * ABS(var1) == ABS(var2)
2950                                          * result = ZERO
2951                                          * ----------
2952                                          */
2953                                         zero_var(result);
2954                                         result->rscale = MAX(var1->rscale, var2->rscale);
2955                                         result->dscale = MAX(var1->dscale, var2->dscale);
2956                                         break;
2957
2958                                 case 1:
2959                                         /* ----------
2960                                          * ABS(var1) > ABS(var2)
2961                                          * result = +(ABS(var1) - ABS(var2))
2962                                          * ----------
2963                                          */
2964                                         sub_abs(var1, var2, result);
2965                                         result->sign = NUMERIC_POS;
2966                                         break;
2967
2968                                 case -1:
2969                                         /* ----------
2970                                          * ABS(var1) < ABS(var2)
2971                                          * result = -(ABS(var2) - ABS(var1))
2972                                          * ----------
2973                                          */
2974                                         sub_abs(var2, var1, result);
2975                                         result->sign = NUMERIC_NEG;
2976                                         break;
2977                         }
2978                 }
2979         }
2980         else
2981         {
2982                 if (var2->sign == NUMERIC_NEG)
2983                 {
2984                         /* ----------
2985                          * Both are negative
2986                          * Must compare absolute values
2987                          * ----------
2988                          */
2989                         switch (cmp_abs(var1, var2))
2990                         {
2991                                 case 0:
2992                                         /* ----------
2993                                          * ABS(var1) == ABS(var2)
2994                                          * result = ZERO
2995                                          * ----------
2996                                          */
2997                                         zero_var(result);
2998                                         result->rscale = MAX(var1->rscale, var2->rscale);
2999                                         result->dscale = MAX(var1->dscale, var2->dscale);
3000                                         break;
3001
3002                                 case 1:
3003                                         /* ----------
3004                                          * ABS(var1) > ABS(var2)
3005                                          * result = -(ABS(var1) - ABS(var2))
3006                                          * ----------
3007                                          */
3008                                         sub_abs(var1, var2, result);
3009                                         result->sign = NUMERIC_NEG;
3010                                         break;
3011
3012                                 case -1:
3013                                         /* ----------
3014                                          * ABS(var1) < ABS(var2)
3015                                          * result = +(ABS(var2) - ABS(var1))
3016                                          * ----------
3017                                          */
3018                                         sub_abs(var2, var1, result);
3019                                         result->sign = NUMERIC_POS;
3020                                         break;
3021                         }
3022                 }
3023                 else
3024                 {
3025                         /* ----------
3026                          * var1 is negative, var2 is positive
3027                          * result = -(ABS(var1) + ABS(var2))
3028                          * ----------
3029                          */
3030                         add_abs(var1, var2, result);
3031                         result->sign = NUMERIC_NEG;
3032                 }
3033         }
3034 }
3035
3036
3037 /* ----------
3038  * mul_var() -
3039  *
3040  *      Multiplication on variable level. Product of var1 * var2 is stored
3041  *      in result.
3042  * ----------
3043  */
3044 static void
3045 mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3046 {
3047         NumericDigit *res_buf;
3048         NumericDigit *res_digits;
3049         int                     res_ndigits;
3050         int                     res_weight;
3051         int                     res_sign;
3052         int                     i,
3053                                 ri,
3054                                 i1,
3055                                 i2;
3056         long            sum = 0;
3057
3058         res_weight = var1->weight + var2->weight + 2;
3059         res_ndigits = var1->ndigits + var2->ndigits + 1;
3060         if (var1->sign == var2->sign)
3061                 res_sign = NUMERIC_POS;
3062         else
3063                 res_sign = NUMERIC_NEG;
3064
3065         res_buf = digitbuf_alloc(res_ndigits);
3066         res_digits = res_buf;
3067         memset(res_digits, 0, res_ndigits);
3068
3069         ri = res_ndigits;
3070         for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
3071         {
3072                 sum = 0;
3073                 i = --ri;
3074
3075                 for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
3076                 {
3077                         sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
3078                         res_digits[i--] = sum % 10;
3079                         sum /= 10;
3080                 }
3081                 res_digits[i] = sum;
3082         }
3083
3084         i = res_weight + global_rscale + 2;
3085         if (i >= 0 && i < res_ndigits)
3086         {
3087                 sum = (res_digits[i] > 4) ? 1 : 0;
3088                 res_ndigits = i;
3089                 i--;
3090                 while (sum)
3091                 {
3092                         sum += res_digits[i];
3093                         res_digits[i--] = sum % 10;
3094                         sum /= 10;
3095                 }
3096         }
3097
3098         while (res_ndigits > 0 && *res_digits == 0)
3099         {
3100                 res_digits++;
3101                 res_weight--;
3102                 res_ndigits--;
3103         }
3104         while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3105                 res_ndigits--;
3106
3107         if (res_ndigits == 0)
3108         {
3109                 res_sign = NUMERIC_POS;
3110                 res_weight = 0;
3111         }
3112
3113         digitbuf_free(result->buf);
3114         result->buf = res_buf;
3115         result->digits = res_digits;
3116         result->ndigits = res_ndigits;
3117         result->weight = res_weight;
3118         result->rscale = global_rscale;
3119         result->sign = res_sign;
3120 }
3121
3122
3123 /* ----------
3124  * div_var() -
3125  *
3126  *      Division on variable level.
3127  * ----------
3128  */
3129 static void
3130 div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3131 {
3132         NumericDigit *res_digits;
3133         int                     res_ndigits;
3134         int                     res_sign;
3135         int                     res_weight;
3136         NumericVar      dividend;
3137         NumericVar      divisor[10];
3138         int                     ndigits_tmp;
3139         int                     weight_tmp;
3140         int                     rscale_tmp;
3141         int                     ri;
3142         int                     i;
3143         long            guess;
3144         long            first_have;
3145         long            first_div;
3146         int                     first_nextdigit;
3147         int                     stat = 0;
3148
3149         /*
3150          * First of all division by zero check
3151          */
3152         ndigits_tmp = var2->ndigits + 1;
3153         if (ndigits_tmp == 1)
3154                 elog(ERROR, "division by zero on numeric");
3155
3156         /*
3157          * Determine the result sign, weight and number of digits to calculate
3158          */
3159         if (var1->sign == var2->sign)
3160                 res_sign = NUMERIC_POS;
3161         else
3162                 res_sign = NUMERIC_NEG;
3163         res_weight = var1->weight - var2->weight + 1;
3164         res_ndigits = global_rscale + res_weight;
3165         if (res_ndigits <= 0)
3166                 res_ndigits = 1;
3167
3168         /*
3169          * Now result zero check
3170          */
3171         if (var1->ndigits == 0)
3172         {
3173                 zero_var(result);
3174                 result->rscale = global_rscale;
3175                 return;
3176         }
3177
3178         /*
3179          * Initialize local variables
3180          */
3181         init_var(&dividend);
3182         for (i = 1; i < 10; i++)
3183                 init_var(&divisor[i]);
3184
3185         /*
3186          * Make a copy of the divisor which has one leading zero digit
3187          */
3188         divisor[1].ndigits = ndigits_tmp;
3189         divisor[1].rscale = var2->ndigits;
3190         divisor[1].sign = NUMERIC_POS;
3191         divisor[1].buf = digitbuf_alloc(ndigits_tmp);
3192         divisor[1].digits = divisor[1].buf;
3193         divisor[1].digits[0] = 0;
3194         memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
3195
3196         /*
3197          * Make a copy of the dividend
3198          */
3199         dividend.ndigits = var1->ndigits;
3200         dividend.weight = 0;
3201         dividend.rscale = var1->ndigits;
3202         dividend.sign = NUMERIC_POS;
3203         dividend.buf = digitbuf_alloc(var1->ndigits);
3204         dividend.digits = dividend.buf;
3205         memcpy(dividend.digits, var1->digits, var1->ndigits);
3206
3207         /*
3208          * Setup the result
3209          */
3210         digitbuf_free(result->buf);
3211         result->buf = digitbuf_alloc(res_ndigits + 2);
3212         res_digits = result->buf;
3213         result->digits = res_digits;
3214         result->ndigits = res_ndigits;
3215         result->weight = res_weight;
3216         result->rscale = global_rscale;
3217         result->sign = res_sign;
3218         res_digits[0] = 0;
3219
3220         first_div = divisor[1].digits[1] * 10;
3221         if (ndigits_tmp > 2)
3222                 first_div += divisor[1].digits[2];
3223
3224         first_have = 0;
3225         first_nextdigit = 0;
3226
3227         weight_tmp = 1;
3228         rscale_tmp = divisor[1].rscale;
3229
3230         for (ri = 0; ri <= res_ndigits; ri++)
3231         {
3232                 first_have = first_have * 10;
3233                 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
3234                         first_have += dividend.digits[first_nextdigit];
3235                 first_nextdigit++;
3236
3237                 guess = (first_have * 10) / first_div + 1;
3238                 if (guess > 9)
3239                         guess = 9;
3240
3241                 while (guess > 0)
3242                 {
3243                         if (divisor[guess].buf == NULL)
3244                         {
3245                                 int                     i;
3246                                 long            sum = 0;
3247
3248                                 memcpy(&divisor[guess], &divisor[1], sizeof(NumericVar));
3249                                 divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
3250                                 divisor[guess].digits = divisor[guess].buf;
3251                                 for (i = divisor[1].ndigits - 1; i >= 0; i--)
3252                                 {
3253                                         sum += divisor[1].digits[i] * guess;
3254                                         divisor[guess].digits[i] = sum % 10;
3255                                         sum /= 10;
3256                                 }
3257                         }
3258
3259                         divisor[guess].weight = weight_tmp;
3260                         divisor[guess].rscale = rscale_tmp;
3261
3262                         stat = cmp_abs(&dividend, &divisor[guess]);
3263                         if (stat >= 0)
3264                                 break;
3265
3266                         guess--;
3267                 }
3268
3269                 res_digits[ri + 1] = guess;
3270                 if (stat == 0)
3271                 {
3272                         ri++;
3273                         break;
3274                 }
3275
3276                 weight_tmp--;
3277                 rscale_tmp++;
3278
3279                 if (guess == 0)
3280                         continue;
3281
3282                 sub_abs(&dividend, &divisor[guess], &dividend);
3283
3284                 first_nextdigit = dividend.weight - weight_tmp;
3285                 first_have = 0;
3286                 if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
3287                         first_have = dividend.digits[first_nextdigit];
3288                 first_nextdigit++;
3289         }
3290
3291         result->ndigits = ri + 1;
3292         if (ri == res_ndigits + 1)
3293         {
3294                 int                     carry = (res_digits[ri] > 4) ? 1 : 0;
3295
3296                 result->ndigits = ri;
3297                 res_digits[ri] = 0;
3298
3299                 while (carry && ri > 0)
3300                 {
3301                         carry += res_digits[--ri];
3302                         res_digits[ri] = carry % 10;
3303                         carry /= 10;
3304                 }
3305         }
3306
3307         while (result->ndigits > 0 && *(result->digits) == 0)
3308         {
3309                 (result->digits)++;
3310                 (result->weight)--;
3311                 (result->ndigits)--;
3312         }
3313         while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
3314                 (result->ndigits)--;
3315         if (result->ndigits == 0)
3316                 result->sign = NUMERIC_POS;
3317
3318         /*
3319          * Tidy up
3320          */
3321         digitbuf_free(dividend.buf);
3322         for (i = 1; i < 10; i++)
3323                 digitbuf_free(divisor[i].buf);
3324 }
3325
3326
3327 /* ----------
3328  * mod_var() -
3329  *
3330  *      Calculate the modulo of two numerics at variable level
3331  * ----------
3332  */
3333 static void
3334 mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
3335 {
3336         NumericVar      tmp;
3337         int                     save_global_rscale;
3338         int                     div_dscale;
3339
3340         init_var(&tmp);
3341
3342         /* ---------
3343          * We do this using the equation
3344          *              mod(x,y) = x - trunc(x/y)*y
3345          * We set global_rscale the same way numeric_div and numeric_mul do
3346          * to get the right answer from the equation.  The final result,
3347          * however, need not be displayed to more precision than the inputs.
3348          * ----------
3349          */
3350         save_global_rscale = global_rscale;
3351
3352         div_dscale = MAX(var1->dscale + var2->dscale, NUMERIC_MIN_DISPLAY_SCALE);
3353         div_dscale = MIN(div_dscale, NUMERIC_MAX_DISPLAY_SCALE);
3354         global_rscale = MAX(var1->rscale + var2->rscale,
3355                                                 NUMERIC_MIN_RESULT_SCALE);
3356         global_rscale = MAX(global_rscale, div_dscale + 4);
3357         global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
3358
3359         div_var(var1, var2, &tmp);
3360
3361         tmp.dscale = div_dscale;
3362
3363         /* do trunc() by forgetting digits to the right of the decimal point */
3364         tmp.ndigits = MAX(0, MIN(tmp.ndigits, tmp.weight + 1));
3365
3366         global_rscale = var2->rscale + tmp.rscale;
3367
3368         mul_var(var2, &tmp, &tmp);
3369
3370         sub_var(var1, &tmp, result);
3371
3372         result->dscale = MAX(var1->dscale, var2->dscale);
3373
3374         global_rscale = save_global_rscale;
3375         free_var(&tmp);
3376 }
3377
3378
3379 /* ----------
3380  * ceil_var() -
3381  *
3382  *      Return the smallest integer greater than or equal to the argument
3383  *      on variable level
3384  * ----------
3385  */
3386 static void
3387 ceil_var(NumericVar *var, NumericVar *result)
3388 {
3389         NumericVar      tmp;
3390
3391         init_var(&tmp);
3392         set_var_from_var(var, &tmp);
3393
3394         tmp.rscale = 0;
3395         tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
3396         if (tmp.sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
3397                 add_var(&tmp, &const_one, &tmp);
3398
3399         set_var_from_var(&tmp, result);
3400         free_var(&tmp);
3401 }
3402
3403
3404 /* ----------
3405  * floor_var() -
3406  *
3407  *      Return the largest integer equal to or less than the argument
3408  *      on variable level
3409  * ----------
3410  */
3411 static void
3412 floor_var(NumericVar *var, NumericVar *result)
3413 {
3414         NumericVar      tmp;
3415
3416         init_var(&tmp);
3417         set_var_from_var(var, &tmp);
3418
3419         tmp.rscale = 0;
3420         tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1));
3421         if (tmp.sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
3422                 sub_var(&tmp, &const_one, &tmp);
3423
3424         set_var_from_var(&tmp, result);
3425         free_var(&tmp);
3426 }
3427
3428
3429 /* ----------
3430  * sqrt_var() -
3431  *
3432  *      Compute the square root of x using Newtons algorithm
3433  * ----------
3434  */
3435 static void
3436 sqrt_var(NumericVar *arg, NumericVar *result)
3437 {
3438         NumericVar      tmp_arg;
3439         NumericVar      tmp_val;
3440         NumericVar      last_val;
3441         int                     res_rscale;
3442         int                     save_global_rscale;
3443         int                     stat;
3444
3445         save_global_rscale = global_rscale;
3446         global_rscale += 8;
3447         res_rscale = global_rscale;
3448
3449         stat = cmp_var(arg, &const_zero);
3450         if (stat == 0)
3451         {
3452                 set_var_from_var(&const_zero, result);
3453                 result->rscale = res_rscale;
3454                 result->sign = NUMERIC_POS;
3455                 return;
3456         }
3457
3458         if (stat < 0)
3459                 elog(ERROR, "math error on numeric - cannot compute SQRT of negative value");
3460
3461         init_var(&tmp_arg);
3462         init_var(&tmp_val);
3463         init_var(&last_val);
3464
3465         set_var_from_var(arg, &tmp_arg);
3466         set_var_from_var(result, &last_val);
3467
3468         /*
3469          * Initialize the result to the first guess
3470          */
3471         digitbuf_free(result->buf);
3472         result->buf = digitbuf_alloc(1);
3473         result->digits = result->buf;
3474         result->digits[0] = tmp_arg.digits[0] / 2;
3475         if (result->digits[0] == 0)
3476                 result->digits[0] = 1;
3477         result->ndigits = 1;
3478         result->weight = tmp_arg.weight / 2;
3479         result->rscale = res_rscale;
3480         result->sign = NUMERIC_POS;
3481
3482         for (;;)
3483         {
3484                 div_var(&tmp_arg, result, &tmp_val);
3485
3486                 add_var(result, &tmp_val, result);
3487                 div_var(result, &const_two, result);
3488
3489                 if (cmp_var(&last_val, result) == 0)
3490                         break;
3491                 set_var_from_var(result, &last_val);
3492         }
3493
3494         free_var(&last_val);
3495         free_var(&tmp_val);
3496         free_var(&tmp_arg);
3497
3498         global_rscale = save_global_rscale;
3499         div_var(result, &const_one, result);
3500 }
3501
3502
3503 /* ----------
3504  * exp_var() -
3505  *
3506  *      Raise e to the power of x
3507  * ----------
3508  */
3509 static void
3510 exp_var(NumericVar *arg, NumericVar *result)
3511 {
3512         NumericVar      x;
3513         NumericVar      xpow;
3514         NumericVar      ifac;
3515         NumericVar      elem;
3516         NumericVar      ni;
3517         int                     d;
3518         int                     i;
3519         int                     ndiv2 = 0;
3520         bool            xneg = FALSE;
3521         int                     save_global_rscale;
3522
3523         init_var(&x);
3524         init_var(&xpow);
3525         init_var(&ifac);
3526         init_var(&elem);
3527         init_var(&ni);
3528
3529         set_var_from_var(arg, &x);
3530
3531         if (x.sign == NUMERIC_NEG)
3532         {
3533                 xneg = TRUE;
3534                 x.sign = NUMERIC_POS;
3535         }
3536
3537         save_global_rscale = global_rscale;
3538         global_rscale = 0;
3539         for (i = x.weight, d = 0; i >= 0; i--, d++)
3540         {
3541                 global_rscale *= 10;
3542                 if (d < x.ndigits)
3543                         global_rscale += x.digits[d];
3544                 if (global_rscale >= 1000)
3545                         elog(ERROR, "argument for EXP() too big");
3546         }
3547
3548         global_rscale = global_rscale / 2 + save_global_rscale + 8;
3549
3550         while (cmp_var(&x, &const_one) > 0)
3551         {
3552                 ndiv2++;
3553                 global_rscale++;
3554                 div_var(&x, &const_two, &x);
3555         }
3556
3557         add_var(&const_one, &x, result);
3558         set_var_from_var(&x, &xpow);
3559         set_var_from_var(&const_one, &ifac);
3560         set_var_from_var(&const_one, &ni);
3561
3562         for (i = 2;; i++)
3563         {
3564                 add_var(&ni, &const_one, &ni);
3565                 mul_var(&xpow, &x, &xpow);
3566                 mul_var(&ifac, &ni, &ifac);
3567                 div_var(&xpow, &ifac, &elem);
3568
3569                 if (elem.ndigits == 0)
3570                         break;
3571
3572                 add_var(result, &elem, result);
3573         }
3574
3575         while (ndiv2-- > 0)
3576                 mul_var(result, result, result);
3577
3578         global_rscale = save_global_rscale;
3579         if (xneg)
3580                 div_var(&const_one, result, result);
3581         else
3582                 div_var(result, &const_one, result);
3583
3584         result->sign = NUMERIC_POS;
3585
3586         free_var(&x);
3587         free_var(&xpow);
3588         free_var(&ifac);
3589         free_var(&elem);
3590         free_var(&ni);
3591 }
3592
3593
3594 /* ----------
3595  * ln_var() -
3596  *
3597  *      Compute the natural log of x
3598  * ----------
3599  */
3600 static void
3601 ln_var(NumericVar *arg, NumericVar *result)
3602 {
3603         NumericVar      x;
3604         NumericVar      xx;
3605         NumericVar      ni;
3606         NumericVar      elem;
3607         NumericVar      fact;
3608         int                     i;
3609         int                     save_global_rscale;
3610
3611         if (cmp_var(arg, &const_zero) <= 0)
3612                 elog(ERROR, "math error on numeric - cannot compute LN of value <= zero");
3613
3614         save_global_rscale = global_rscale;
3615         global_rscale += 8;
3616
3617         init_var(&x);
3618         init_var(&xx);
3619         init_var(&ni);
3620         init_var(&elem);
3621         init_var(&fact);
3622
3623         set_var_from_var(&const_two, &fact);
3624         set_var_from_var(arg, &x);
3625
3626         while (cmp_var(&x, &const_two) >= 0)
3627         {
3628                 sqrt_var(&x, &x);
3629                 mul_var(&fact, &const_two, &fact);
3630         }
3631         set_var_from_str("0.5", &elem);
3632         while (cmp_var(&x, &elem) <= 0)
3633         {
3634                 sqrt_var(&x, &x);
3635                 mul_var(&fact, &const_two, &fact);
3636         }
3637
3638         sub_var(&x, &const_one, result);
3639         add_var(&x, &const_one, &elem);
3640         div_var(result, &elem, result);
3641         set_var_from_var(result, &xx);
3642         mul_var(result, result, &x);
3643
3644         set_var_from_var(&const_one, &ni);
3645
3646         for (i = 2;; i++)
3647         {
3648                 add_var(&ni, &const_two, &ni);
3649                 mul_var(&xx, &x, &xx);
3650                 div_var(&xx, &ni, &elem);
3651
3652                 if (cmp_var(&elem, &const_zero) == 0)
3653                         break;
3654
3655                 add_var(result, &elem, result);
3656         }
3657
3658         global_rscale = save_global_rscale;
3659         mul_var(result, &fact, result);
3660
3661         free_var(&x);
3662         free_var(&xx);
3663         free_var(&ni);
3664         free_var(&elem);
3665         free_var(&fact);
3666 }
3667
3668
3669 /* ----------
3670  * log_var() -
3671  *
3672  *      Compute the logarithm of x in a given base
3673  * ----------
3674  */
3675 static void
3676 log_var(NumericVar *base, NumericVar *num, NumericVar *result)
3677 {
3678         NumericVar      ln_base;
3679         NumericVar      ln_num;
3680
3681         global_rscale += 8;
3682
3683         init_var(&ln_base);
3684         init_var(&ln_num);
3685
3686         ln_var(base, &ln_base);
3687         ln_var(num, &ln_num);
3688
3689         global_rscale -= 8;
3690
3691         div_var(&ln_num, &ln_base, result);
3692
3693         free_var(&ln_num);
3694         free_var(&ln_base);
3695 }
3696
3697
3698 /* ----------
3699  * power_var() -
3700  *
3701  *      Raise base to the power of exp
3702  * ----------
3703  */
3704 static void
3705 power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
3706 {
3707         NumericVar      ln_base;
3708         NumericVar      ln_num;
3709         int                     save_global_rscale;
3710
3711         save_global_rscale = global_rscale;
3712         global_rscale += global_rscale / 3 + 8;
3713
3714         init_var(&ln_base);
3715         init_var(&ln_num);
3716
3717         ln_var(base, &ln_base);
3718         mul_var(&ln_base, exp, &ln_num);
3719
3720         global_rscale = save_global_rscale;
3721
3722         exp_var(&ln_num, result);
3723
3724         free_var(&ln_num);
3725         free_var(&ln_base);
3726
3727 }
3728
3729
3730 /* ----------------------------------------------------------------------
3731  *
3732  * Following are the lowest level functions that operate unsigned
3733  * on the variable level
3734  *
3735  * ----------------------------------------------------------------------
3736  */
3737
3738
3739 /* ----------
3740  * cmp_abs() -
3741  *
3742  *      Compare the absolute values of var1 and var2
3743  *      Returns:        -1 for ABS(var1) < ABS(var2)
3744  *                              0  for ABS(var1) == ABS(var2)
3745  *                              1  for ABS(var1) > ABS(var2)
3746  * ----------
3747  */
3748 static int
3749 cmp_abs(NumericVar *var1, NumericVar *var2)
3750 {
3751         int                     i1 = 0;
3752         int                     i2 = 0;
3753         int                     w1 = var1->weight;
3754         int                     w2 = var2->weight;
3755         int                     stat;
3756
3757         while (w1 > w2 && i1 < var1->ndigits)
3758         {
3759                 if (var1->digits[i1++] != 0)
3760                         return 1;
3761                 w1--;
3762         }
3763         while (w2 > w1 && i2 < var2->ndigits)
3764         {
3765                 if (var2->digits[i2++] != 0)
3766                         return -1;
3767                 w2--;
3768         }
3769
3770         if (w1 == w2)
3771         {
3772                 while (i1 < var1->ndigits && i2 < var2->ndigits)
3773                 {
3774                         stat = var1->digits[i1++] - var2->digits[i2++];
3775                         if (stat)
3776                         {
3777                                 if (stat > 0)
3778                                         return 1;
3779                                 return -1;
3780                         }
3781                 }
3782         }
3783
3784         while (i1 < var1->ndigits)
3785         {
3786                 if (var1->digits[i1++] != 0)
3787                         return 1;
3788         }
3789         while (i2 < var2->ndigits)
3790         {
3791                 if (var2->digits[i2++] != 0)
3792                         return -1;
3793         }
3794
3795         return 0;
3796 }
3797
3798
3799 /* ----------
3800  * add_abs() -
3801  *
3802  *      Add the absolute values of two variables into result.
3803  *      result might point to one of the operands without danger.
3804  * ----------
3805  */
3806 static void
3807 add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
3808 {
3809         NumericDigit *res_buf;
3810         NumericDigit *res_digits;
3811         int                     res_ndigits;
3812         int                     res_weight;
3813         int                     res_rscale;
3814         int                     res_dscale;
3815         int                     i,
3816                                 i1,
3817                                 i2;
3818         int                     carry = 0;
3819
3820         /* copy these values into local vars for speed in inner loop */
3821         int                     var1ndigits = var1->ndigits;
3822         int                     var2ndigits = var2->ndigits;
3823         NumericDigit *var1digits = var1->digits;
3824         NumericDigit *var2digits = var2->digits;
3825
3826         res_weight = MAX(var1->weight, var2->weight) + 1;
3827         res_rscale = MAX(var1->rscale, var2->rscale);
3828         res_dscale = MAX(var1->dscale, var2->dscale);
3829         res_ndigits = res_rscale + res_weight + 1;
3830         if (res_ndigits <= 0)
3831                 res_ndigits = 1;
3832
3833         res_buf = digitbuf_alloc(res_ndigits);
3834         res_digits = res_buf;
3835
3836         i1 = res_rscale + var1->weight + 1;
3837         i2 = res_rscale + var2->weight + 1;
3838         for (i = res_ndigits - 1; i >= 0; i--)
3839         {
3840                 i1--;
3841                 i2--;
3842                 if (i1 >= 0 && i1 < var1ndigits)
3843                         carry += var1digits[i1];
3844                 if (i2 >= 0 && i2 < var2ndigits)
3845                         carry += var2digits[i2];
3846
3847                 if (carry >= 10)
3848                 {
3849                         res_digits[i] = carry - 10;
3850                         carry = 1;
3851                 }
3852                 else
3853                 {
3854                         res_digits[i] = carry;
3855                         carry = 0;
3856                 }
3857         }
3858
3859         Assert(carry == 0);                     /* else we failed to allow for carry out */
3860
3861         while (res_ndigits > 0 && *res_digits == 0)
3862         {
3863                 res_digits++;
3864                 res_weight--;
3865                 res_ndigits--;
3866         }
3867         while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3868                 res_ndigits--;
3869
3870         if (res_ndigits == 0)
3871                 res_weight = 0;
3872
3873         digitbuf_free(result->buf);
3874         result->ndigits = res_ndigits;
3875         result->buf = res_buf;
3876         result->digits = res_digits;
3877         result->weight = res_weight;
3878         result->rscale = res_rscale;
3879         result->dscale = res_dscale;
3880 }
3881
3882
3883 /* ----------
3884  * sub_abs() -
3885  *
3886  *      Subtract the absolute value of var2 from the absolute value of var1
3887  *      and store in result. result might point to one of the operands
3888  *      without danger.
3889  *
3890  *      ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
3891  * ----------
3892  */
3893 static void
3894 sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
3895 {
3896         NumericDigit *res_buf;
3897         NumericDigit *res_digits;
3898         int                     res_ndigits;
3899         int                     res_weight;
3900         int                     res_rscale;
3901         int                     res_dscale;
3902         int                     i,
3903                                 i1,
3904                                 i2;
3905         int                     borrow = 0;
3906
3907         /* copy these values into local vars for speed in inner loop */
3908         int                     var1ndigits = var1->ndigits;
3909         int                     var2ndigits = var2->ndigits;
3910         NumericDigit *var1digits = var1->digits;
3911         NumericDigit *var2digits = var2->digits;
3912
3913         res_weight = var1->weight;
3914         res_rscale = MAX(var1->rscale, var2->rscale);
3915         res_dscale = MAX(var1->dscale, var2->dscale);
3916         res_ndigits = res_rscale + res_weight + 1;
3917         if (res_ndigits <= 0)
3918                 res_ndigits = 1;
3919
3920         res_buf = digitbuf_alloc(res_ndigits);
3921         res_digits = res_buf;
3922
3923         i1 = res_rscale + var1->weight + 1;
3924         i2 = res_rscale + var2->weight + 1;
3925         for (i = res_ndigits - 1; i >= 0; i--)
3926         {
3927                 i1--;
3928                 i2--;
3929                 if (i1 >= 0 && i1 < var1ndigits)
3930                         borrow += var1digits[i1];
3931                 if (i2 >= 0 && i2 < var2ndigits)
3932                         borrow -= var2digits[i2];
3933
3934                 if (borrow < 0)
3935                 {
3936                         res_digits[i] = borrow + 10;
3937                         borrow = -1;
3938                 }
3939                 else
3940                 {
3941                         res_digits[i] = borrow;
3942                         borrow = 0;
3943                 }
3944         }
3945
3946         Assert(borrow == 0);            /* else caller gave us var1 < var2 */
3947
3948         while (res_ndigits > 0 && *res_digits == 0)
3949         {
3950                 res_digits++;
3951                 res_weight--;
3952                 res_ndigits--;
3953         }
3954         while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
3955                 res_ndigits--;
3956
3957         if (res_ndigits == 0)
3958                 res_weight = 0;
3959
3960         digitbuf_free(result->buf);
3961         result->ndigits = res_ndigits;
3962         result->buf = res_buf;
3963         result->digits = res_digits;
3964         result->weight = res_weight;
3965         result->rscale = res_rscale;
3966         result->dscale = res_dscale;
3967 }