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

Generated by: LCOV version 1.14