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

Generated by: LCOV version 1.13