LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - cash.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 82.8 % 413 342 18 23 30 4 201 6 131 37 189 4
Current Date: 2023-04-08 15:15:32 Functions: 94.6 % 37 35 2 33 1 1 2 33
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * cash.c
       3                 :  * Written by D'Arcy J.M. Cain
       4                 :  * darcy@druid.net
       5                 :  * http://www.druid.net/darcy/
       6                 :  *
       7                 :  * Functions to allow input and output of money normally but store
       8                 :  * and handle it as 64 bit ints
       9                 :  *
      10                 :  * A slightly modified version of this file and a discussion of the
      11                 :  * workings can be found in the book "Software Solutions in C" by
      12                 :  * Dale Schumacher, Academic Press, ISBN: 0-12-632360-7 except that
      13                 :  * this version handles 64 bit numbers and so can hold values up to
      14                 :  * $92,233,720,368,547,758.07.
      15                 :  *
      16                 :  * src/backend/utils/adt/cash.c
      17                 :  */
      18                 : 
      19                 : #include "postgres.h"
      20                 : 
      21                 : #include <limits.h>
      22                 : #include <ctype.h>
      23                 : #include <math.h>
      24                 : 
      25                 : #include "common/int.h"
      26                 : #include "libpq/pqformat.h"
      27                 : #include "utils/builtins.h"
      28                 : #include "utils/cash.h"
      29                 : #include "utils/numeric.h"
      30                 : #include "utils/pg_locale.h"
      31                 : 
      32                 : 
      33                 : /*************************************************************************
      34                 :  * Private routines
      35                 :  ************************************************************************/
      36                 : 
      37                 : static const char *
      38 CBC       11586 : num_word(Cash value)
      39                 : {
      40                 :     static char buf[128];
      41                 :     static const char *const small[] = {
      42                 :         "zero", "one", "two", "three", "four", "five", "six", "seven",
      43                 :         "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
      44                 :         "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty",
      45                 :         "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
      46                 :     };
      47           11586 :     const char *const *big = small + 18;
      48           11586 :     int         tu = value % 100;
      49                 : 
      50                 :     /* deal with the simple cases first */
      51           11586 :     if (value <= 20)
      52           11319 :         return small[value];
      53                 : 
      54                 :     /* is it an even multiple of 100? */
      55             267 :     if (!tu)
      56                 :     {
      57 UBC           0 :         sprintf(buf, "%s hundred", small[value / 100]);
      58               0 :         return buf;
      59                 :     }
      60                 : 
      61                 :     /* more than 99? */
      62 CBC         267 :     if (value > 99)
      63                 :     {
      64                 :         /* is it an even multiple of 10 other than 10? */
      65               6 :         if (value % 10 == 0 && tu > 10)
      66 UBC           0 :             sprintf(buf, "%s hundred %s",
      67               0 :                     small[value / 100], big[tu / 10]);
      68 CBC           6 :         else if (tu < 20)
      69 UBC           0 :             sprintf(buf, "%s hundred and %s",
      70               0 :                     small[value / 100], small[tu]);
      71                 :         else
      72 CBC           6 :             sprintf(buf, "%s hundred %s %s",
      73               6 :                     small[value / 100], big[tu / 10], small[tu % 10]);
      74                 :     }
      75                 :     else
      76                 :     {
      77                 :         /* is it an even multiple of 10 other than 10? */
      78             261 :         if (value % 10 == 0 && tu > 10)
      79 UBC           0 :             sprintf(buf, "%s", big[tu / 10]);
      80 CBC         261 :         else if (tu < 20)
      81 UBC           0 :             sprintf(buf, "%s", small[tu]);
      82                 :         else
      83 CBC         261 :             sprintf(buf, "%s %s", big[tu / 10], small[tu % 10]);
      84                 :     }
      85                 : 
      86             267 :     return buf;
      87                 : }                               /* num_word() */
      88                 : 
      89                 : /* cash_in()
      90                 :  * Convert a string to a cash data type.
      91                 :  * Format is [$]###[,]###[.##]
      92                 :  * Examples: 123.45 $123.45 $123,456.78
      93                 :  *
      94                 :  */
      95                 : Datum
      96             832 : cash_in(PG_FUNCTION_ARGS)
      97                 : {
      98             832 :     char       *str = PG_GETARG_CSTRING(0);
      99 GNC         832 :     Node       *escontext = fcinfo->context;
     100 ECB             :     Cash        result;
     101 GIC         832 :     Cash        value = 0;
     102 CBC         832 :     Cash        dec = 0;
     103             832 :     Cash        sgn = 1;
     104             832 :     bool        seen_dot = false;
     105             832 :     const char *s = str;
     106 ECB             :     int         fpoint;
     107                 :     char        dsymbol;
     108                 :     const char *ssymbol,
     109                 :                *psymbol,
     110                 :                *nsymbol,
     111                 :                *csymbol;
     112 GIC         832 :     struct lconv *lconvert = PGLC_localeconv();
     113 ECB             : 
     114                 :     /*
     115                 :      * frac_digits will be CHAR_MAX in some locales, notably C.  However, just
     116                 :      * testing for == CHAR_MAX is risky, because of compilers like gcc that
     117                 :      * "helpfully" let you alter the platform-standard definition of whether
     118                 :      * char is signed or not.  If we are so unfortunate as to get compiled
     119                 :      * with a nonstandard -fsigned-char or -funsigned-char switch, then our
     120                 :      * idea of CHAR_MAX will not agree with libc's. The safest course is not
     121                 :      * to test for CHAR_MAX at all, but to impose a range check for plausible
     122                 :      * frac_digits values.
     123                 :      */
     124 GIC         832 :     fpoint = lconvert->frac_digits;
     125 CBC         832 :     if (fpoint < 0 || fpoint > 10)
     126             832 :         fpoint = 2;             /* best guess in this case, I think */
     127 ECB             : 
     128                 :     /* we restrict dsymbol to be a single byte, but not the other symbols */
     129 GIC         832 :     if (*lconvert->mon_decimal_point != '\0' &&
     130 LBC           0 :         lconvert->mon_decimal_point[1] == '\0')
     131 UBC           0 :         dsymbol = *lconvert->mon_decimal_point;
     132 EUB             :     else
     133 GIC         832 :         dsymbol = '.';
     134 CBC         832 :     if (*lconvert->mon_thousands_sep != '\0')
     135 LBC           0 :         ssymbol = lconvert->mon_thousands_sep;
     136 EUB             :     else                        /* ssymbol should not equal dsymbol */
     137 GIC         832 :         ssymbol = (dsymbol != ',') ? "," : ".";
     138 CBC         832 :     csymbol = (*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$";
     139             832 :     psymbol = (*lconvert->positive_sign != '\0') ? lconvert->positive_sign : "+";
     140             832 :     nsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";
     141 ECB             : 
     142                 : #ifdef CASHDEBUG
     143                 :     printf("cashin- precision '%d'; decimal '%c'; thousands '%s'; currency '%s'; positive '%s'; negative '%s'\n",
     144                 :            fpoint, dsymbol, ssymbol, csymbol, psymbol, nsymbol);
     145                 : #endif
     146                 : 
     147                 :     /* we need to add all sorts of checking here.  For now just */
     148                 :     /* strip all leading whitespace and any leading currency symbol */
     149 GIC         832 :     while (isspace((unsigned char) *s))
     150 LBC           0 :         s++;
     151 GBC         832 :     if (strncmp(s, csymbol, strlen(csymbol)) == 0)
     152 CBC          62 :         s += strlen(csymbol);
     153             832 :     while (isspace((unsigned char) *s))
     154 LBC           0 :         s++;
     155 EUB             : 
     156                 : #ifdef CASHDEBUG
     157                 :     printf("cashin- string is '%s'\n", s);
     158                 : #endif
     159                 : 
     160                 :     /* a leading minus or paren signifies a negative number */
     161                 :     /* again, better heuristics needed */
     162                 :     /* XXX - doesn't properly check for balanced parens - djmc */
     163 GIC         832 :     if (strncmp(s, nsymbol, strlen(nsymbol)) == 0)
     164 ECB             :     {
     165 GIC         305 :         sgn = -1;
     166 CBC         305 :         s += strlen(nsymbol);
     167 ECB             :     }
     168 GIC         527 :     else if (*s == '(')
     169 ECB             :     {
     170 GIC           6 :         sgn = -1;
     171 CBC           6 :         s++;
     172 ECB             :     }
     173 GIC         521 :     else if (strncmp(s, psymbol, strlen(psymbol)) == 0)
     174 LBC           0 :         s += strlen(psymbol);
     175 EUB             : 
     176                 : #ifdef CASHDEBUG
     177                 :     printf("cashin- string is '%s'\n", s);
     178                 : #endif
     179                 : 
     180                 :     /* allow whitespace and currency symbol after the sign, too */
     181 GIC         832 :     while (isspace((unsigned char) *s))
     182 LBC           0 :         s++;
     183 GBC         832 :     if (strncmp(s, csymbol, strlen(csymbol)) == 0)
     184 CBC           3 :         s += strlen(csymbol);
     185             832 :     while (isspace((unsigned char) *s))
     186 LBC           0 :         s++;
     187 EUB             : 
     188                 : #ifdef CASHDEBUG
     189                 :     printf("cashin- string is '%s'\n", s);
     190                 : #endif
     191                 : 
     192                 :     /*
     193                 :      * We accumulate the absolute amount in "value" and then apply the sign at
     194                 :      * the end.  (The sign can appear before or after the digits, so it would
     195                 :      * be more complicated to do otherwise.)  Because of the larger range of
     196                 :      * negative signed integers, we build "value" in the negative and then
     197                 :      * flip the sign at the end, catching most-negative-number overflow if
     198                 :      * necessary.
     199                 :      */
     200                 : 
     201 GIC        7887 :     for (; *s; s++)
     202 ECB             :     {
     203                 :         /*
     204                 :          * We look for digits as long as we have found less than the required
     205                 :          * number of decimal places.
     206                 :          */
     207 GIC        7097 :         if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint))
     208 CBC        6320 :         {
     209            6329 :             int8        digit = *s - '0';
     210 ECB             : 
     211 GIC       12652 :             if (pg_mul_s64_overflow(value, 10, &value) ||
     212 CBC        6323 :                 pg_sub_s64_overflow(value, digit, &value))
     213 GNC           9 :                 ereturn(escontext, (Datum) 0,
     214 ECB             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     215                 :                          errmsg("value \"%s\" is out of range for type %s",
     216                 :                                 str, "money")));
     217                 : 
     218 GIC        6320 :             if (seen_dot)
     219 CBC        1455 :                 dec++;
     220 ECB             :         }
     221                 :         /* decimal point? then start counting fractions... */
     222 GIC         768 :         else if (*s == dsymbol && !seen_dot)
     223 ECB             :         {
     224 GIC         732 :             seen_dot = true;
     225 ECB             :         }
     226                 :         /* ignore if "thousands" separator, else we're done */
     227 GIC          36 :         else if (strncmp(s, ssymbol, strlen(ssymbol)) == 0)
     228 CBC           3 :             s += strlen(ssymbol) - 1;
     229 ECB             :         else
     230 GIC          33 :             break;
     231 ECB             :     }
     232                 : 
     233                 :     /* round off if there's another digit */
     234 GIC         823 :     if (isdigit((unsigned char) *s) && *s >= '5')
     235 ECB             :     {
     236                 :         /* remember we build the value in the negative */
     237 GIC          15 :         if (pg_sub_s64_overflow(value, 1, &value))
     238 GNC           3 :             ereturn(escontext, (Datum) 0,
     239 ECB             :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     240                 :                      errmsg("value \"%s\" is out of range for type %s",
     241                 :                             str, "money")));
     242                 :     }
     243                 : 
     244                 :     /* adjust for less than required decimal places */
     245 GIC        1002 :     for (; dec < fpoint; dec++)
     246 ECB             :     {
     247 GIC         194 :         if (pg_mul_s64_overflow(value, 10, &value))
     248 GNC          12 :             ereturn(escontext, (Datum) 0,
     249 ECB             :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     250                 :                      errmsg("value \"%s\" is out of range for type %s",
     251                 :                             str, "money")));
     252                 :     }
     253                 : 
     254                 :     /*
     255                 :      * should only be trailing digits followed by whitespace, right paren,
     256                 :      * trailing sign, and/or trailing currency symbol
     257                 :      */
     258 GIC         826 :     while (isdigit((unsigned char) *s))
     259 CBC          18 :         s++;
     260 ECB             : 
     261 GIC         814 :     while (*s)
     262 ECB             :     {
     263 GIC          12 :         if (isspace((unsigned char) *s) || *s == ')')
     264 CBC           6 :             s++;
     265               6 :         else if (strncmp(s, nsymbol, strlen(nsymbol)) == 0)
     266 ECB             :         {
     267 UIC           0 :             sgn = -1;
     268 UBC           0 :             s += strlen(nsymbol);
     269 EUB             :         }
     270 GIC           6 :         else if (strncmp(s, psymbol, strlen(psymbol)) == 0)
     271 LBC           0 :             s += strlen(psymbol);
     272 GBC           6 :         else if (strncmp(s, csymbol, strlen(csymbol)) == 0)
     273 LBC           0 :             s += strlen(csymbol);
     274 EUB             :         else
     275 GNC           6 :             ereturn(escontext, (Datum) 0,
     276 ECB             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     277                 :                      errmsg("invalid input syntax for type %s: \"%s\"",
     278                 :                             "money", str)));
     279                 :     }
     280                 : 
     281                 :     /*
     282                 :      * If the value is supposed to be positive, flip the sign, but check for
     283                 :      * the most negative number.
     284                 :      */
     285 GIC         802 :     if (sgn > 0)
     286 ECB             :     {
     287 GIC         503 :         if (value == PG_INT64_MIN)
     288 GNC           6 :             ereturn(escontext, (Datum) 0,
     289 ECB             :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     290                 :                      errmsg("value \"%s\" is out of range for type %s",
     291                 :                             str, "money")));
     292 GIC         497 :         result = -value;
     293 ECB             :     }
     294                 :     else
     295 GIC         299 :         result = value;
     296 ECB             : 
     297                 : #ifdef CASHDEBUG
     298                 :     printf("cashin- result is " INT64_FORMAT "\n", result);
     299                 : #endif
     300                 : 
     301 GIC         796 :     PG_RETURN_CASH(result);
     302 ECB             : }
     303                 : 
     304                 : 
     305                 : /* cash_out()
     306                 :  * Function to convert cash to a dollars and cents representation, using
     307                 :  * the lc_monetary locale's formatting.
     308                 :  */
     309                 : Datum
     310 GIC         613 : cash_out(PG_FUNCTION_ARGS)
     311 ECB             : {
     312 GIC         613 :     Cash        value = PG_GETARG_CASH(0);
     313 ECB             :     char       *result;
     314                 :     char        buf[128];
     315                 :     char       *bufptr;
     316                 :     int         digit_pos;
     317                 :     int         points,
     318                 :                 mon_group;
     319                 :     char        dsymbol;
     320                 :     const char *ssymbol,
     321                 :                *csymbol,
     322                 :                *signsymbol;
     323                 :     char        sign_posn,
     324                 :                 cs_precedes,
     325                 :                 sep_by_space;
     326 GIC         613 :     struct lconv *lconvert = PGLC_localeconv();
     327 ECB             : 
     328                 :     /* see comments about frac_digits in cash_in() */
     329 GIC         613 :     points = lconvert->frac_digits;
     330 CBC         613 :     if (points < 0 || points > 10)
     331             613 :         points = 2;             /* best guess in this case, I think */
     332 ECB             : 
     333                 :     /*
     334                 :      * As with frac_digits, must apply a range check to mon_grouping to avoid
     335                 :      * being fooled by variant CHAR_MAX values.
     336                 :      */
     337 GIC         613 :     mon_group = *lconvert->mon_grouping;
     338 CBC         613 :     if (mon_group <= 0 || mon_group > 6)
     339             613 :         mon_group = 3;
     340 ECB             : 
     341                 :     /* we restrict dsymbol to be a single byte, but not the other symbols */
     342 GIC         613 :     if (*lconvert->mon_decimal_point != '\0' &&
     343 LBC           0 :         lconvert->mon_decimal_point[1] == '\0')
     344 UBC           0 :         dsymbol = *lconvert->mon_decimal_point;
     345 EUB             :     else
     346 GIC         613 :         dsymbol = '.';
     347 CBC         613 :     if (*lconvert->mon_thousands_sep != '\0')
     348 LBC           0 :         ssymbol = lconvert->mon_thousands_sep;
     349 EUB             :     else                        /* ssymbol should not equal dsymbol */
     350 GIC         613 :         ssymbol = (dsymbol != ',') ? "," : ".";
     351 CBC         613 :     csymbol = (*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$";
     352 ECB             : 
     353 GIC         613 :     if (value < 0)
     354 ECB             :     {
     355                 :         /* make the amount positive for digit-reconstruction loop */
     356 GIC          43 :         value = -value;
     357 ECB             :         /* set up formatting data */
     358 GIC          43 :         signsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";
     359 CBC          43 :         sign_posn = lconvert->n_sign_posn;
     360              43 :         cs_precedes = lconvert->n_cs_precedes;
     361              43 :         sep_by_space = lconvert->n_sep_by_space;
     362 ECB             :     }
     363                 :     else
     364                 :     {
     365 GIC         570 :         signsymbol = lconvert->positive_sign;
     366 CBC         570 :         sign_posn = lconvert->p_sign_posn;
     367             570 :         cs_precedes = lconvert->p_cs_precedes;
     368             570 :         sep_by_space = lconvert->p_sep_by_space;
     369 ECB             :     }
     370                 : 
     371                 :     /* we build the digits+decimal-point+sep string right-to-left in buf[] */
     372 GIC         613 :     bufptr = buf + sizeof(buf) - 1;
     373 CBC         613 :     *bufptr = '\0';
     374 ECB             : 
     375                 :     /*
     376                 :      * Generate digits till there are no non-zero digits left and we emitted
     377                 :      * at least one to the left of the decimal point.  digit_pos is the
     378                 :      * current digit position, with zero as the digit just left of the decimal
     379                 :      * point, increasing to the right.
     380                 :      */
     381 GIC         613 :     digit_pos = points;
     382 ECB             :     do
     383                 :     {
     384 GIC        3689 :         if (points && digit_pos == 0)
     385 ECB             :         {
     386                 :             /* insert decimal point, but not if value cannot be fractional */
     387 GIC         613 :             *(--bufptr) = dsymbol;
     388 ECB             :         }
     389 GIC        3076 :         else if (digit_pos < 0 && (digit_pos % mon_group) == 0)
     390 ECB             :         {
     391                 :             /* insert thousands sep, but only to left of radix point */
     392 GIC         513 :             bufptr -= strlen(ssymbol);
     393 CBC         513 :             memcpy(bufptr, ssymbol, strlen(ssymbol));
     394 ECB             :         }
     395                 : 
     396 GIC        3689 :         *(--bufptr) = ((uint64) value % 10) + '0';
     397 CBC        3689 :         value = ((uint64) value) / 10;
     398            3689 :         digit_pos--;
     399            3689 :     } while (value || digit_pos >= 0);
     400 ECB             : 
     401                 :     /*----------
     402                 :      * Now, attach currency symbol and sign symbol in the correct order.
     403                 :      *
     404                 :      * The POSIX spec defines these values controlling this code:
     405                 :      *
     406                 :      * p/n_sign_posn:
     407                 :      *  0   Parentheses enclose the quantity and the currency_symbol.
     408                 :      *  1   The sign string precedes the quantity and the currency_symbol.
     409                 :      *  2   The sign string succeeds the quantity and the currency_symbol.
     410                 :      *  3   The sign string precedes the currency_symbol.
     411                 :      *  4   The sign string succeeds the currency_symbol.
     412                 :      *
     413                 :      * p/n_cs_precedes: 0 means currency symbol after value, else before it.
     414                 :      *
     415                 :      * p/n_sep_by_space:
     416                 :      *  0   No <space> separates the currency symbol and value.
     417                 :      *  1   If the currency symbol and sign string are adjacent, a <space>
     418                 :      *      separates them from the value; otherwise, a <space> separates
     419                 :      *      the currency symbol from the value.
     420                 :      *  2   If the currency symbol and sign string are adjacent, a <space>
     421                 :      *      separates them; otherwise, a <space> separates the sign string
     422                 :      *      from the value.
     423                 :      *----------
     424                 :      */
     425 GIC         613 :     switch (sign_posn)
     426 ECB             :     {
     427 UIC           0 :         case 0:
     428 UBC           0 :             if (cs_precedes)
     429               0 :                 result = psprintf("(%s%s%s)",
     430 EUB             :                                   csymbol,
     431                 :                                   (sep_by_space == 1) ? " " : "",
     432                 :                                   bufptr);
     433                 :             else
     434 UIC           0 :                 result = psprintf("(%s%s%s)",
     435 EUB             :                                   bufptr,
     436                 :                                   (sep_by_space == 1) ? " " : "",
     437                 :                                   csymbol);
     438 UIC           0 :             break;
     439 GBC         613 :         case 1:
     440 ECB             :         default:
     441 GIC         613 :             if (cs_precedes)
     442 CBC         613 :                 result = psprintf("%s%s%s%s%s",
     443 ECB             :                                   signsymbol,
     444                 :                                   (sep_by_space == 2) ? " " : "",
     445                 :                                   csymbol,
     446                 :                                   (sep_by_space == 1) ? " " : "",
     447                 :                                   bufptr);
     448                 :             else
     449 UIC           0 :                 result = psprintf("%s%s%s%s%s",
     450 EUB             :                                   signsymbol,
     451                 :                                   (sep_by_space == 2) ? " " : "",
     452                 :                                   bufptr,
     453                 :                                   (sep_by_space == 1) ? " " : "",
     454                 :                                   csymbol);
     455 GIC         613 :             break;
     456 LBC           0 :         case 2:
     457 UBC           0 :             if (cs_precedes)
     458               0 :                 result = psprintf("%s%s%s%s%s",
     459 EUB             :                                   csymbol,
     460                 :                                   (sep_by_space == 1) ? " " : "",
     461                 :                                   bufptr,
     462                 :                                   (sep_by_space == 2) ? " " : "",
     463                 :                                   signsymbol);
     464                 :             else
     465 UIC           0 :                 result = psprintf("%s%s%s%s%s",
     466 EUB             :                                   bufptr,
     467                 :                                   (sep_by_space == 1) ? " " : "",
     468                 :                                   csymbol,
     469                 :                                   (sep_by_space == 2) ? " " : "",
     470                 :                                   signsymbol);
     471 UIC           0 :             break;
     472 UBC           0 :         case 3:
     473               0 :             if (cs_precedes)
     474               0 :                 result = psprintf("%s%s%s%s%s",
     475 EUB             :                                   signsymbol,
     476                 :                                   (sep_by_space == 2) ? " " : "",
     477                 :                                   csymbol,
     478                 :                                   (sep_by_space == 1) ? " " : "",
     479                 :                                   bufptr);
     480                 :             else
     481 UIC           0 :                 result = psprintf("%s%s%s%s%s",
     482 EUB             :                                   bufptr,
     483                 :                                   (sep_by_space == 1) ? " " : "",
     484                 :                                   signsymbol,
     485                 :                                   (sep_by_space == 2) ? " " : "",
     486                 :                                   csymbol);
     487 UIC           0 :             break;
     488 UBC           0 :         case 4:
     489               0 :             if (cs_precedes)
     490               0 :                 result = psprintf("%s%s%s%s%s",
     491 EUB             :                                   csymbol,
     492                 :                                   (sep_by_space == 2) ? " " : "",
     493                 :                                   signsymbol,
     494                 :                                   (sep_by_space == 1) ? " " : "",
     495                 :                                   bufptr);
     496                 :             else
     497 UIC           0 :                 result = psprintf("%s%s%s%s%s",
     498 EUB             :                                   bufptr,
     499                 :                                   (sep_by_space == 1) ? " " : "",
     500                 :                                   csymbol,
     501                 :                                   (sep_by_space == 2) ? " " : "",
     502                 :                                   signsymbol);
     503 UIC           0 :             break;
     504 EUB             :     }
     505                 : 
     506 GIC         613 :     PG_RETURN_CSTRING(result);
     507 ECB             : }
     508                 : 
     509                 : /*
     510                 :  *      cash_recv           - converts external binary format to cash
     511                 :  */
     512                 : Datum
     513 UIC           0 : cash_recv(PG_FUNCTION_ARGS)
     514 EUB             : {
     515 UIC           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     516 EUB             : 
     517 UIC           0 :     PG_RETURN_CASH((Cash) pq_getmsgint64(buf));
     518 EUB             : }
     519                 : 
     520                 : /*
     521                 :  *      cash_send           - converts cash to binary format
     522                 :  */
     523                 : Datum
     524 UIC           0 : cash_send(PG_FUNCTION_ARGS)
     525 EUB             : {
     526 UIC           0 :     Cash        arg1 = PG_GETARG_CASH(0);
     527 EUB             :     StringInfoData buf;
     528                 : 
     529 UIC           0 :     pq_begintypsend(&buf);
     530 UBC           0 :     pq_sendint64(&buf, arg1);
     531               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     532 EUB             : }
     533                 : 
     534                 : /*
     535                 :  * Comparison functions
     536                 :  */
     537                 : 
     538                 : Datum
     539 GIC         577 : cash_eq(PG_FUNCTION_ARGS)
     540 ECB             : {
     541 GIC         577 :     Cash        c1 = PG_GETARG_CASH(0);
     542 CBC         577 :     Cash        c2 = PG_GETARG_CASH(1);
     543 ECB             : 
     544 GIC         577 :     PG_RETURN_BOOL(c1 == c2);
     545 ECB             : }
     546                 : 
     547                 : Datum
     548 GIC          33 : cash_ne(PG_FUNCTION_ARGS)
     549 ECB             : {
     550 GIC          33 :     Cash        c1 = PG_GETARG_CASH(0);
     551 CBC          33 :     Cash        c2 = PG_GETARG_CASH(1);
     552 ECB             : 
     553 GIC          33 :     PG_RETURN_BOOL(c1 != c2);
     554 ECB             : }
     555                 : 
     556                 : Datum
     557 GIC         549 : cash_lt(PG_FUNCTION_ARGS)
     558 ECB             : {
     559 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
     560 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
     561 ECB             : 
     562 GIC         549 :     PG_RETURN_BOOL(c1 < c2);
     563 ECB             : }
     564                 : 
     565                 : Datum
     566 GIC         549 : cash_le(PG_FUNCTION_ARGS)
     567 ECB             : {
     568 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
     569 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
     570 ECB             : 
     571 GIC         549 :     PG_RETURN_BOOL(c1 <= c2);
     572 ECB             : }
     573                 : 
     574                 : Datum
     575 GIC         549 : cash_gt(PG_FUNCTION_ARGS)
     576 ECB             : {
     577 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
     578 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
     579 ECB             : 
     580 GIC         549 :     PG_RETURN_BOOL(c1 > c2);
     581 ECB             : }
     582                 : 
     583                 : Datum
     584 GIC         549 : cash_ge(PG_FUNCTION_ARGS)
     585 ECB             : {
     586 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
     587 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
     588 ECB             : 
     589 GIC         549 :     PG_RETURN_BOOL(c1 >= c2);
     590 ECB             : }
     591                 : 
     592                 : Datum
     593 GIC         731 : cash_cmp(PG_FUNCTION_ARGS)
     594 ECB             : {
     595 GIC         731 :     Cash        c1 = PG_GETARG_CASH(0);
     596 CBC         731 :     Cash        c2 = PG_GETARG_CASH(1);
     597 ECB             : 
     598 GIC         731 :     if (c1 > c2)
     599 CBC         585 :         PG_RETURN_INT32(1);
     600             146 :     else if (c1 == c2)
     601              16 :         PG_RETURN_INT32(0);
     602 ECB             :     else
     603 GIC         130 :         PG_RETURN_INT32(-1);
     604 ECB             : }
     605                 : 
     606                 : 
     607                 : /* cash_pl()
     608                 :  * Add two cash values.
     609                 :  */
     610                 : Datum
     611 GIC          21 : cash_pl(PG_FUNCTION_ARGS)
     612 ECB             : {
     613 GIC          21 :     Cash        c1 = PG_GETARG_CASH(0);
     614 CBC          21 :     Cash        c2 = PG_GETARG_CASH(1);
     615 ECB             :     Cash        result;
     616                 : 
     617 GIC          21 :     result = c1 + c2;
     618 ECB             : 
     619 GIC          21 :     PG_RETURN_CASH(result);
     620 ECB             : }
     621                 : 
     622                 : 
     623                 : /* cash_mi()
     624                 :  * Subtract two cash values.
     625                 :  */
     626                 : Datum
     627 GIC           6 : cash_mi(PG_FUNCTION_ARGS)
     628 ECB             : {
     629 GIC           6 :     Cash        c1 = PG_GETARG_CASH(0);
     630 CBC           6 :     Cash        c2 = PG_GETARG_CASH(1);
     631 ECB             :     Cash        result;
     632                 : 
     633 GIC           6 :     result = c1 - c2;
     634 ECB             : 
     635 GIC           6 :     PG_RETURN_CASH(result);
     636 ECB             : }
     637                 : 
     638                 : 
     639                 : /* cash_div_cash()
     640                 :  * Divide cash by cash, returning float8.
     641                 :  */
     642                 : Datum
     643 GIC           3 : cash_div_cash(PG_FUNCTION_ARGS)
     644 ECB             : {
     645 GIC           3 :     Cash        dividend = PG_GETARG_CASH(0);
     646 CBC           3 :     Cash        divisor = PG_GETARG_CASH(1);
     647 ECB             :     float8      quotient;
     648                 : 
     649 GIC           3 :     if (divisor == 0)
     650 LBC           0 :         ereport(ERROR,
     651 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     652                 :                  errmsg("division by zero")));
     653                 : 
     654 GIC           3 :     quotient = (float8) dividend / (float8) divisor;
     655 CBC           3 :     PG_RETURN_FLOAT8(quotient);
     656 ECB             : }
     657                 : 
     658                 : 
     659                 : /* cash_mul_flt8()
     660                 :  * Multiply cash by float8.
     661                 :  */
     662                 : Datum
     663 GIC           3 : cash_mul_flt8(PG_FUNCTION_ARGS)
     664 ECB             : {
     665 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
     666 CBC           3 :     float8      f = PG_GETARG_FLOAT8(1);
     667 ECB             :     Cash        result;
     668                 : 
     669 GIC           3 :     result = rint(c * f);
     670 CBC           3 :     PG_RETURN_CASH(result);
     671 ECB             : }
     672                 : 
     673                 : 
     674                 : /* flt8_mul_cash()
     675                 :  * Multiply float8 by cash.
     676                 :  */
     677                 : Datum
     678 GIC           3 : flt8_mul_cash(PG_FUNCTION_ARGS)
     679 ECB             : {
     680 GIC           3 :     float8      f = PG_GETARG_FLOAT8(0);
     681 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
     682 ECB             :     Cash        result;
     683                 : 
     684 GIC           3 :     result = rint(f * c);
     685 CBC           3 :     PG_RETURN_CASH(result);
     686 ECB             : }
     687                 : 
     688                 : 
     689                 : /* cash_div_flt8()
     690                 :  * Divide cash by float8.
     691                 :  */
     692                 : Datum
     693 GIC           6 : cash_div_flt8(PG_FUNCTION_ARGS)
     694 ECB             : {
     695 GIC           6 :     Cash        c = PG_GETARG_CASH(0);
     696 CBC           6 :     float8      f = PG_GETARG_FLOAT8(1);
     697 ECB             :     Cash        result;
     698                 : 
     699 GIC           6 :     if (f == 0.0)
     700 LBC           0 :         ereport(ERROR,
     701 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     702                 :                  errmsg("division by zero")));
     703                 : 
     704 GIC           6 :     result = rint(c / f);
     705 CBC           6 :     PG_RETURN_CASH(result);
     706 ECB             : }
     707                 : 
     708                 : 
     709                 : /* cash_mul_flt4()
     710                 :  * Multiply cash by float4.
     711                 :  */
     712                 : Datum
     713 GIC           3 : cash_mul_flt4(PG_FUNCTION_ARGS)
     714 ECB             : {
     715 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
     716 CBC           3 :     float4      f = PG_GETARG_FLOAT4(1);
     717 ECB             :     Cash        result;
     718                 : 
     719 GIC           3 :     result = rint(c * (float8) f);
     720 CBC           3 :     PG_RETURN_CASH(result);
     721 ECB             : }
     722                 : 
     723                 : 
     724                 : /* flt4_mul_cash()
     725                 :  * Multiply float4 by cash.
     726                 :  */
     727                 : Datum
     728 GIC           3 : flt4_mul_cash(PG_FUNCTION_ARGS)
     729 ECB             : {
     730 GIC           3 :     float4      f = PG_GETARG_FLOAT4(0);
     731 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
     732 ECB             :     Cash        result;
     733                 : 
     734 GIC           3 :     result = rint((float8) f * c);
     735 CBC           3 :     PG_RETURN_CASH(result);
     736 ECB             : }
     737                 : 
     738                 : 
     739                 : /* cash_div_flt4()
     740                 :  * Divide cash by float4.
     741                 :  *
     742                 :  */
     743                 : Datum
     744 GIC           6 : cash_div_flt4(PG_FUNCTION_ARGS)
     745 ECB             : {
     746 GIC           6 :     Cash        c = PG_GETARG_CASH(0);
     747 CBC           6 :     float4      f = PG_GETARG_FLOAT4(1);
     748 ECB             :     Cash        result;
     749                 : 
     750 GIC           6 :     if (f == 0.0)
     751 LBC           0 :         ereport(ERROR,
     752 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     753                 :                  errmsg("division by zero")));
     754                 : 
     755 GIC           6 :     result = rint(c / (float8) f);
     756 CBC           6 :     PG_RETURN_CASH(result);
     757 ECB             : }
     758                 : 
     759                 : 
     760                 : /* cash_mul_int8()
     761                 :  * Multiply cash by int8.
     762                 :  */
     763                 : Datum
     764 GIC           3 : cash_mul_int8(PG_FUNCTION_ARGS)
     765 ECB             : {
     766 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
     767 CBC           3 :     int64       i = PG_GETARG_INT64(1);
     768 ECB             :     Cash        result;
     769                 : 
     770 GIC           3 :     result = c * i;
     771 CBC           3 :     PG_RETURN_CASH(result);
     772 ECB             : }
     773                 : 
     774                 : 
     775                 : /* int8_mul_cash()
     776                 :  * Multiply int8 by cash.
     777                 :  */
     778                 : Datum
     779 GIC           3 : int8_mul_cash(PG_FUNCTION_ARGS)
     780 ECB             : {
     781 GIC           3 :     int64       i = PG_GETARG_INT64(0);
     782 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
     783 ECB             :     Cash        result;
     784                 : 
     785 GIC           3 :     result = i * c;
     786 CBC           3 :     PG_RETURN_CASH(result);
     787 ECB             : }
     788                 : 
     789                 : /* cash_div_int8()
     790                 :  * Divide cash by 8-byte integer.
     791                 :  */
     792                 : Datum
     793 GIC           9 : cash_div_int8(PG_FUNCTION_ARGS)
     794 ECB             : {
     795 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
     796 CBC           9 :     int64       i = PG_GETARG_INT64(1);
     797 ECB             :     Cash        result;
     798                 : 
     799 GIC           9 :     if (i == 0)
     800 LBC           0 :         ereport(ERROR,
     801 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     802                 :                  errmsg("division by zero")));
     803                 : 
     804 GIC           9 :     result = c / i;
     805 ECB             : 
     806 GIC           9 :     PG_RETURN_CASH(result);
     807 ECB             : }
     808                 : 
     809                 : 
     810                 : /* cash_mul_int4()
     811                 :  * Multiply cash by int4.
     812                 :  */
     813                 : Datum
     814 GIC           3 : cash_mul_int4(PG_FUNCTION_ARGS)
     815 ECB             : {
     816 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
     817 CBC           3 :     int32       i = PG_GETARG_INT32(1);
     818 ECB             :     Cash        result;
     819                 : 
     820 GIC           3 :     result = c * i;
     821 CBC           3 :     PG_RETURN_CASH(result);
     822 ECB             : }
     823                 : 
     824                 : 
     825                 : /* int4_mul_cash()
     826                 :  * Multiply int4 by cash.
     827                 :  */
     828                 : Datum
     829 GIC           3 : int4_mul_cash(PG_FUNCTION_ARGS)
     830 ECB             : {
     831 GIC           3 :     int32       i = PG_GETARG_INT32(0);
     832 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
     833 ECB             :     Cash        result;
     834                 : 
     835 GIC           3 :     result = i * c;
     836 CBC           3 :     PG_RETURN_CASH(result);
     837 ECB             : }
     838                 : 
     839                 : 
     840                 : /* cash_div_int4()
     841                 :  * Divide cash by 4-byte integer.
     842                 :  *
     843                 :  */
     844                 : Datum
     845 GIC           9 : cash_div_int4(PG_FUNCTION_ARGS)
     846 ECB             : {
     847 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
     848 CBC           9 :     int32       i = PG_GETARG_INT32(1);
     849 ECB             :     Cash        result;
     850                 : 
     851 GIC           9 :     if (i == 0)
     852 LBC           0 :         ereport(ERROR,
     853 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     854                 :                  errmsg("division by zero")));
     855                 : 
     856 GIC           9 :     result = c / i;
     857 ECB             : 
     858 GIC           9 :     PG_RETURN_CASH(result);
     859 ECB             : }
     860                 : 
     861                 : 
     862                 : /* cash_mul_int2()
     863                 :  * Multiply cash by int2.
     864                 :  */
     865                 : Datum
     866 GIC           3 : cash_mul_int2(PG_FUNCTION_ARGS)
     867 ECB             : {
     868 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
     869 CBC           3 :     int16       s = PG_GETARG_INT16(1);
     870 ECB             :     Cash        result;
     871                 : 
     872 GIC           3 :     result = c * s;
     873 CBC           3 :     PG_RETURN_CASH(result);
     874 ECB             : }
     875                 : 
     876                 : /* int2_mul_cash()
     877                 :  * Multiply int2 by cash.
     878                 :  */
     879                 : Datum
     880 GIC           3 : int2_mul_cash(PG_FUNCTION_ARGS)
     881 ECB             : {
     882 GIC           3 :     int16       s = PG_GETARG_INT16(0);
     883 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
     884 ECB             :     Cash        result;
     885                 : 
     886 GIC           3 :     result = s * c;
     887 CBC           3 :     PG_RETURN_CASH(result);
     888 ECB             : }
     889                 : 
     890                 : /* cash_div_int2()
     891                 :  * Divide cash by int2.
     892                 :  *
     893                 :  */
     894                 : Datum
     895 GIC           9 : cash_div_int2(PG_FUNCTION_ARGS)
     896 ECB             : {
     897 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
     898 CBC           9 :     int16       s = PG_GETARG_INT16(1);
     899 ECB             :     Cash        result;
     900                 : 
     901 GIC           9 :     if (s == 0)
     902 LBC           0 :         ereport(ERROR,
     903 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
     904                 :                  errmsg("division by zero")));
     905                 : 
     906 GIC           9 :     result = c / s;
     907 CBC           9 :     PG_RETURN_CASH(result);
     908 ECB             : }
     909                 : 
     910                 : /* cashlarger()
     911                 :  * Return larger of two cash values.
     912                 :  */
     913                 : Datum
     914 GIC           3 : cashlarger(PG_FUNCTION_ARGS)
     915 ECB             : {
     916 GIC           3 :     Cash        c1 = PG_GETARG_CASH(0);
     917 CBC           3 :     Cash        c2 = PG_GETARG_CASH(1);
     918 ECB             :     Cash        result;
     919                 : 
     920 GIC           3 :     result = (c1 > c2) ? c1 : c2;
     921 ECB             : 
     922 GIC           3 :     PG_RETURN_CASH(result);
     923 ECB             : }
     924                 : 
     925                 : /* cashsmaller()
     926                 :  * Return smaller of two cash values.
     927                 :  */
     928                 : Datum
     929 GIC           3 : cashsmaller(PG_FUNCTION_ARGS)
     930 ECB             : {
     931 GIC           3 :     Cash        c1 = PG_GETARG_CASH(0);
     932 CBC           3 :     Cash        c2 = PG_GETARG_CASH(1);
     933 ECB             :     Cash        result;
     934                 : 
     935 GIC           3 :     result = (c1 < c2) ? c1 : c2;
     936 ECB             : 
     937 GIC           3 :     PG_RETURN_CASH(result);
     938 ECB             : }
     939                 : 
     940                 : /* cash_words()
     941                 :  * This converts an int4 as well but to a representation using words
     942                 :  * Obviously way North American centric - sorry
     943                 :  */
     944                 : Datum
     945 GIC        6006 : cash_words(PG_FUNCTION_ARGS)
     946 ECB             : {
     947 GIC        6006 :     Cash        value = PG_GETARG_CASH(0);
     948 ECB             :     uint64      val;
     949                 :     char        buf[256];
     950 GIC        6006 :     char       *p = buf;
     951 ECB             :     Cash        m0;
     952                 :     Cash        m1;
     953                 :     Cash        m2;
     954                 :     Cash        m3;
     955                 :     Cash        m4;
     956                 :     Cash        m5;
     957                 :     Cash        m6;
     958                 : 
     959                 :     /* work with positive numbers */
     960 GIC        6006 :     if (value < 0)
     961 ECB             :     {
     962 UIC           0 :         value = -value;
     963 UBC           0 :         strcpy(buf, "minus ");
     964               0 :         p += 6;
     965 EUB             :     }
     966                 :     else
     967 GIC        6006 :         buf[0] = '\0';
     968 ECB             : 
     969                 :     /* Now treat as unsigned, to avoid trouble at INT_MIN */
     970 GIC        6006 :     val = (uint64) value;
     971 ECB             : 
     972 GIC        6006 :     m0 = val % INT64CONST(100); /* cents */
     973 CBC        6006 :     m1 = (val / INT64CONST(100)) % 1000;    /* hundreds */
     974            6006 :     m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
     975            6006 :     m3 = (val / INT64CONST(100000000)) % 1000;  /* millions */
     976            6006 :     m4 = (val / INT64CONST(100000000000)) % 1000;   /* billions */
     977            6006 :     m5 = (val / INT64CONST(100000000000000)) % 1000;    /* trillions */
     978            6006 :     m6 = (val / INT64CONST(100000000000000000)) % 1000; /* quadrillions */
     979 ECB             : 
     980 GIC        6006 :     if (m6)
     981 ECB             :     {
     982 UIC           0 :         strcat(buf, num_word(m6));
     983 UBC           0 :         strcat(buf, " quadrillion ");
     984 EUB             :     }
     985                 : 
     986 GIC        6006 :     if (m5)
     987 ECB             :     {
     988 UIC           0 :         strcat(buf, num_word(m5));
     989 UBC           0 :         strcat(buf, " trillion ");
     990 EUB             :     }
     991                 : 
     992 GIC        6006 :     if (m4)
     993 ECB             :     {
     994 UIC           0 :         strcat(buf, num_word(m4));
     995 UBC           0 :         strcat(buf, " billion ");
     996 EUB             :     }
     997                 : 
     998 GIC        6006 :     if (m3)
     999 ECB             :     {
    1000 UIC           0 :         strcat(buf, num_word(m3));
    1001 UBC           0 :         strcat(buf, " million ");
    1002 EUB             :     }
    1003                 : 
    1004 GIC        6006 :     if (m2)
    1005 ECB             :     {
    1006 UIC           0 :         strcat(buf, num_word(m2));
    1007 UBC           0 :         strcat(buf, " thousand ");
    1008 EUB             :     }
    1009                 : 
    1010 GIC        6006 :     if (m1)
    1011 CBC        5580 :         strcat(buf, num_word(m1));
    1012 ECB             : 
    1013 GIC        6006 :     if (!*p)
    1014 CBC         426 :         strcat(buf, "zero");
    1015 ECB             : 
    1016 GIC        6006 :     strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
    1017 CBC        6006 :     strcat(buf, num_word(m0));
    1018            6006 :     strcat(buf, m0 == 1 ? " cent" : " cents");
    1019 ECB             : 
    1020                 :     /* capitalize output */
    1021 GIC        6006 :     buf[0] = pg_toupper((unsigned char) buf[0]);
    1022 ECB             : 
    1023                 :     /* return as text datum */
    1024 GIC        6006 :     PG_RETURN_TEXT_P(cstring_to_text(buf));
    1025 ECB             : }
    1026                 : 
    1027                 : 
    1028                 : /* cash_numeric()
    1029                 :  * Convert cash to numeric.
    1030                 :  */
    1031                 : Datum
    1032 GIC          12 : cash_numeric(PG_FUNCTION_ARGS)
    1033 ECB             : {
    1034 GIC          12 :     Cash        money = PG_GETARG_CASH(0);
    1035 ECB             :     Datum       result;
    1036                 :     int         fpoint;
    1037 GIC          12 :     struct lconv *lconvert = PGLC_localeconv();
    1038 ECB             : 
    1039                 :     /* see comments about frac_digits in cash_in() */
    1040 GIC          12 :     fpoint = lconvert->frac_digits;
    1041 CBC          12 :     if (fpoint < 0 || fpoint > 10)
    1042              12 :         fpoint = 2;
    1043 ECB             : 
    1044                 :     /* convert the integral money value to numeric */
    1045 GIC          12 :     result = NumericGetDatum(int64_to_numeric(money));
    1046 ECB             : 
    1047                 :     /* scale appropriately, if needed */
    1048 GIC          12 :     if (fpoint > 0)
    1049 ECB             :     {
    1050                 :         int64       scale;
    1051                 :         int         i;
    1052                 :         Datum       numeric_scale;
    1053                 :         Datum       quotient;
    1054                 : 
    1055                 :         /* compute required scale factor */
    1056 GIC          12 :         scale = 1;
    1057 CBC          36 :         for (i = 0; i < fpoint; i++)
    1058              24 :             scale *= 10;
    1059              12 :         numeric_scale = NumericGetDatum(int64_to_numeric(scale));
    1060 ECB             : 
    1061                 :         /*
    1062                 :          * Given integral inputs approaching INT64_MAX, select_div_scale()
    1063                 :          * might choose a result scale of zero, causing loss of fractional
    1064                 :          * digits in the quotient.  We can ensure an exact result by setting
    1065                 :          * the dscale of either input to be at least as large as the desired
    1066                 :          * result scale.  numeric_round() will do that for us.
    1067                 :          */
    1068 GIC          12 :         numeric_scale = DirectFunctionCall2(numeric_round,
    1069 ECB             :                                             numeric_scale,
    1070                 :                                             Int32GetDatum(fpoint));
    1071                 : 
    1072                 :         /* Now we can safely divide ... */
    1073 GIC          12 :         quotient = DirectFunctionCall2(numeric_div, result, numeric_scale);
    1074 ECB             : 
    1075                 :         /* ... and forcibly round to exactly the intended number of digits */
    1076 GIC          12 :         result = DirectFunctionCall2(numeric_round,
    1077 ECB             :                                      quotient,
    1078                 :                                      Int32GetDatum(fpoint));
    1079                 :     }
    1080                 : 
    1081 GIC          12 :     PG_RETURN_DATUM(result);
    1082 ECB             : }
    1083                 : 
    1084                 : /* numeric_cash()
    1085                 :  * Convert numeric to cash.
    1086                 :  */
    1087                 : Datum
    1088 GIC           6 : numeric_cash(PG_FUNCTION_ARGS)
    1089 ECB             : {
    1090 GIC           6 :     Datum       amount = PG_GETARG_DATUM(0);
    1091 ECB             :     Cash        result;
    1092                 :     int         fpoint;
    1093                 :     int64       scale;
    1094                 :     int         i;
    1095                 :     Datum       numeric_scale;
    1096 GIC           6 :     struct lconv *lconvert = PGLC_localeconv();
    1097 ECB             : 
    1098                 :     /* see comments about frac_digits in cash_in() */
    1099 GIC           6 :     fpoint = lconvert->frac_digits;
    1100 CBC           6 :     if (fpoint < 0 || fpoint > 10)
    1101               6 :         fpoint = 2;
    1102 ECB             : 
    1103                 :     /* compute required scale factor */
    1104 GIC           6 :     scale = 1;
    1105 CBC          18 :     for (i = 0; i < fpoint; i++)
    1106              12 :         scale *= 10;
    1107 ECB             : 
    1108                 :     /* multiply the input amount by scale factor */
    1109 GIC           6 :     numeric_scale = NumericGetDatum(int64_to_numeric(scale));
    1110 CBC           6 :     amount = DirectFunctionCall2(numeric_mul, amount, numeric_scale);
    1111 ECB             : 
    1112                 :     /* note that numeric_int8 will round to nearest integer for us */
    1113 GIC           6 :     result = DatumGetInt64(DirectFunctionCall1(numeric_int8, amount));
    1114 ECB             : 
    1115 GIC           6 :     PG_RETURN_CASH(result);
    1116 ECB             : }
    1117                 : 
    1118                 : /* int4_cash()
    1119                 :  * Convert int4 (int) to cash
    1120                 :  */
    1121                 : Datum
    1122 GIC        6072 : int4_cash(PG_FUNCTION_ARGS)
    1123 ECB             : {
    1124 GIC        6072 :     int32       amount = PG_GETARG_INT32(0);
    1125 ECB             :     Cash        result;
    1126                 :     int         fpoint;
    1127                 :     int64       scale;
    1128                 :     int         i;
    1129 GIC        6072 :     struct lconv *lconvert = PGLC_localeconv();
    1130 ECB             : 
    1131                 :     /* see comments about frac_digits in cash_in() */
    1132 GIC        6072 :     fpoint = lconvert->frac_digits;
    1133 CBC        6072 :     if (fpoint < 0 || fpoint > 10)
    1134            6072 :         fpoint = 2;
    1135 ECB             : 
    1136                 :     /* compute required scale factor */
    1137 GIC        6072 :     scale = 1;
    1138 CBC       18216 :     for (i = 0; i < fpoint; i++)
    1139           12144 :         scale *= 10;
    1140 ECB             : 
    1141                 :     /* compute amount * scale, checking for overflow */
    1142 GIC        6072 :     result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
    1143 ECB             :                                                Int64GetDatum(scale)));
    1144                 : 
    1145 GIC        6072 :     PG_RETURN_CASH(result);
    1146 ECB             : }
    1147                 : 
    1148                 : /* int8_cash()
    1149                 :  * Convert int8 (bigint) to cash
    1150                 :  */
    1151                 : Datum
    1152 GIC          12 : int8_cash(PG_FUNCTION_ARGS)
    1153 ECB             : {
    1154 GIC          12 :     int64       amount = PG_GETARG_INT64(0);
    1155 ECB             :     Cash        result;
    1156                 :     int         fpoint;
    1157                 :     int64       scale;
    1158                 :     int         i;
    1159 GIC          12 :     struct lconv *lconvert = PGLC_localeconv();
    1160 ECB             : 
    1161                 :     /* see comments about frac_digits in cash_in() */
    1162 GIC          12 :     fpoint = lconvert->frac_digits;
    1163 CBC          12 :     if (fpoint < 0 || fpoint > 10)
    1164              12 :         fpoint = 2;
    1165 ECB             : 
    1166                 :     /* compute required scale factor */
    1167 GIC          12 :     scale = 1;
    1168 CBC          36 :     for (i = 0; i < fpoint; i++)
    1169              24 :         scale *= 10;
    1170 ECB             : 
    1171                 :     /* compute amount * scale, checking for overflow */
    1172 GIC          12 :     result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
    1173 ECB             :                                                Int64GetDatum(scale)));
    1174                 : 
    1175 GIC          12 :     PG_RETURN_CASH(result);
    1176 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a