LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - numeric.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 836 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 29 0
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.3.2-1