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

Generated by: LCOV version 1.13