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 17:13:01 Functions: 94.6 % 37 35 2 33 1 1 2 33
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 6 6 6
Legend: Lines: hit not hit (240..) days: 82.6 % 407 336 18 23 30 4 201 131 37 189
Function coverage date bins:
(240..) days: 48.6 % 72 35 2 33 1 1 2 33

 Age         Owner                  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 *
 5940 darcy                      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                 :     };
 1637 andres                     47           11586 :     const char *const *big = small + 18;
 5940 darcy                      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                 :     {
 5940 darcy                      57 UBC           0 :         sprintf(buf, "%s hundred", small[value / 100]);
                                 58               0 :         return buf;
                                 59                 :     }
                                 60                 : 
                                 61                 :     /* more than 99? */
 5940 darcy                      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)
 5940 darcy                      66 UBC           0 :             sprintf(buf, "%s hundred %s",
                                 67               0 :                     small[value / 100], big[tu / 10]);
 5940 darcy                      68 CBC           6 :         else if (tu < 20)
 5940 darcy                      69 UBC           0 :             sprintf(buf, "%s hundred and %s",
                                 70               0 :                     small[value / 100], small[tu]);
                                 71                 :         else
 5940 darcy                      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)
 5940 darcy                      79 UBC           0 :             sprintf(buf, "%s", big[tu / 10]);
 5940 darcy                      80 CBC         261 :         else if (tu < 20)
 5940 darcy                      81 UBC           0 :             sprintf(buf, "%s", small[tu]);
                                 82                 :         else
 5940 darcy                      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
 8284 tgl                        96             832 : cash_in(PG_FUNCTION_ARGS)
                                 97                 : {
                                 98             832 :     char       *str = PG_GETARG_CSTRING(0);
  116 tgl                        99 GNC         832 :     Node       *escontext = fcinfo->context;
 8284 tgl                       100 ECB             :     Cash        result;
 9344 bruce                     101 GIC         832 :     Cash        value = 0;
 9344 bruce                     102 CBC         832 :     Cash        dec = 0;
                                103             832 :     Cash        sgn = 1;
 4180 tgl                       104             832 :     bool        seen_dot = false;
 9344 bruce                     105             832 :     const char *s = str;
 9344 bruce                     106 ECB             :     int         fpoint;
                                107                 :     char        dsymbol;
                                108                 :     const char *ssymbol,
                                109                 :                *psymbol,
                                110                 :                *nsymbol,
                                111                 :                *csymbol;
 8170 tgl                       112 GIC         832 :     struct lconv *lconvert = PGLC_localeconv();
 8053 bruce                     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                 :      */
 8177 tgl                       124 GIC         832 :     fpoint = lconvert->frac_digits;
 8177 tgl                       125 CBC         832 :     if (fpoint < 0 || fpoint > 10)
                                126             832 :         fpoint = 2;             /* best guess in this case, I think */
 9345 bruce                     127 ECB             : 
                                128                 :     /* we restrict dsymbol to be a single byte, but not the other symbols */
 4180 tgl                       129 GIC         832 :     if (*lconvert->mon_decimal_point != '\0' &&
 4180 tgl                       130 LBC           0 :         lconvert->mon_decimal_point[1] == '\0')
 4180 tgl                       131 UBC           0 :         dsymbol = *lconvert->mon_decimal_point;
 5615 bruce                     132 EUB             :     else
 4180 tgl                       133 GIC         832 :         dsymbol = '.';
 4180 tgl                       134 CBC         832 :     if (*lconvert->mon_thousands_sep != '\0')
 4180 tgl                       135 LBC           0 :         ssymbol = lconvert->mon_thousands_sep;
 2118 tgl                       136 EUB             :     else                        /* ssymbol should not equal dsymbol */
 4180 tgl                       137 GIC         832 :         ssymbol = (dsymbol != ',') ? "," : ".";
 4180 tgl                       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 : "-";
 9490 scrappy                   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 */
 8162 tgl                       149 GIC         832 :     while (isspace((unsigned char) *s))
 8986 bruce                     150 LBC           0 :         s++;
 8986 bruce                     151 GBC         832 :     if (strncmp(s, csymbol, strlen(csymbol)) == 0)
 8986 bruce                     152 CBC          62 :         s += strlen(csymbol);
 4179 tgl                       153             832 :     while (isspace((unsigned char) *s))
 4179 tgl                       154 LBC           0 :         s++;
 9169 lockhart                  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 */
 8986 bruce                     163 GIC         832 :     if (strncmp(s, nsymbol, strlen(nsymbol)) == 0)
 9169 lockhart                  164 ECB             :     {
 9169 lockhart                  165 GIC         305 :         sgn = -1;
 9169 lockhart                  166 CBC         305 :         s += strlen(nsymbol);
 9169 lockhart                  167 ECB             :     }
 9169 lockhart                  168 GIC         527 :     else if (*s == '(')
 9345 bruce                     169 ECB             :     {
 9345 bruce                     170 GIC           6 :         sgn = -1;
 9345 bruce                     171 CBC           6 :         s++;
 9345 bruce                     172 ECB             :     }
 4180 tgl                       173 GIC         521 :     else if (strncmp(s, psymbol, strlen(psymbol)) == 0)
 4180 tgl                       174 LBC           0 :         s += strlen(psymbol);
 9490 scrappy                   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 */
 8162 tgl                       181 GIC         832 :     while (isspace((unsigned char) *s))
 8986 bruce                     182 LBC           0 :         s++;
 8986 bruce                     183 GBC         832 :     if (strncmp(s, csymbol, strlen(csymbol)) == 0)
 8986 bruce                     184 CBC           3 :         s += strlen(csymbol);
 4179 tgl                       185             832 :     while (isspace((unsigned char) *s))
 4179 tgl                       186 LBC           0 :         s++;
 9169 lockhart                  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                 : 
 4180 tgl                       201 GIC        7887 :     for (; *s; s++)
 9345 bruce                     202 ECB             :     {
                                203                 :         /*
                                204                 :          * We look for digits as long as we have found less than the required
                                205                 :          * number of decimal places.
                                206                 :          */
 5051 tgl                       207 GIC        7097 :         if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint))
 9345 bruce                     208 CBC        6320 :         {
 1944 andres                    209            6329 :             int8        digit = *s - '0';
 2404 peter_e                   210 ECB             : 
 1944 andres                    211 GIC       12652 :             if (pg_mul_s64_overflow(value, 10, &value) ||
 1944 andres                    212 CBC        6323 :                 pg_sub_s64_overflow(value, digit, &value))
  116 tgl                       213 GNC           9 :                 ereturn(escontext, (Datum) 0,
 2404 peter_e                   214 ECB             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                215                 :                          errmsg("value \"%s\" is out of range for type %s",
                                216                 :                                 str, "money")));
                                217                 : 
 9345 bruce                     218 GIC        6320 :             if (seen_dot)
 9345 bruce                     219 CBC        1455 :                 dec++;
 9345 bruce                     220 ECB             :         }
                                221                 :         /* decimal point? then start counting fractions... */
 9345 bruce                     222 GIC         768 :         else if (*s == dsymbol && !seen_dot)
 9345 bruce                     223 ECB             :         {
 4180 tgl                       224 GIC         732 :             seen_dot = true;
 9345 bruce                     225 ECB             :         }
                                226                 :         /* ignore if "thousands" separator, else we're done */
 4180 tgl                       227 GIC          36 :         else if (strncmp(s, ssymbol, strlen(ssymbol)) == 0)
 4180 tgl                       228 CBC           3 :             s += strlen(ssymbol) - 1;
 4180 tgl                       229 ECB             :         else
 9345 bruce                     230 GIC          33 :             break;
 9490 scrappy                   231 ECB             :     }
                                232                 : 
                                233                 :     /* round off if there's another digit */
 4180 tgl                       234 GIC         823 :     if (isdigit((unsigned char) *s) && *s >= '5')
 1944 andres                    235 ECB             :     {
                                236                 :         /* remember we build the value in the negative */
 1944 andres                    237 GIC          15 :         if (pg_sub_s64_overflow(value, 1, &value))
  116 tgl                       238 GNC           3 :             ereturn(escontext, (Datum) 0,
 1944 andres                    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 */
 4180 tgl                       245 GIC        1002 :     for (; dec < fpoint; dec++)
 2404 peter_e                   246 ECB             :     {
 1944 andres                    247 GIC         194 :         if (pg_mul_s64_overflow(value, 10, &value))
  116 tgl                       248 GNC          12 :             ereturn(escontext, (Datum) 0,
 2404 peter_e                   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                 :      */
 5750 tgl                       258 GIC         826 :     while (isdigit((unsigned char) *s))
 5750 tgl                       259 CBC          18 :         s++;
 4179 tgl                       260 ECB             : 
 4180 tgl                       261 GIC         814 :     while (*s)
 4180 tgl                       262 ECB             :     {
 4180 tgl                       263 GIC          12 :         if (isspace((unsigned char) *s) || *s == ')')
 4180 tgl                       264 CBC           6 :             s++;
                                265               6 :         else if (strncmp(s, nsymbol, strlen(nsymbol)) == 0)
 4180 tgl                       266 ECB             :         {
 4180 tgl                       267 UIC           0 :             sgn = -1;
 4180 tgl                       268 UBC           0 :             s += strlen(nsymbol);
 4180 tgl                       269 EUB             :         }
 4179 tgl                       270 GIC           6 :         else if (strncmp(s, psymbol, strlen(psymbol)) == 0)
 4179 tgl                       271 LBC           0 :             s += strlen(psymbol);
 4179 tgl                       272 GBC           6 :         else if (strncmp(s, csymbol, strlen(csymbol)) == 0)
 4179 tgl                       273 LBC           0 :             s += strlen(csymbol);
 4180 tgl                       274 EUB             :         else
  116 tgl                       275 GNC           6 :             ereturn(escontext, (Datum) 0,
 4180 tgl                       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                 :      */
 2404 peter_e                   285 GIC         802 :     if (sgn > 0)
 2404 peter_e                   286 ECB             :     {
 1944 andres                    287 GIC         503 :         if (value == PG_INT64_MIN)
  116 tgl                       288 GNC           6 :             ereturn(escontext, (Datum) 0,
 2404 peter_e                   289 ECB             :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                290                 :                      errmsg("value \"%s\" is out of range for type %s",
                                291                 :                             str, "money")));
 1944 andres                    292 GIC         497 :         result = -value;
 2404 peter_e                   293 ECB             :     }
                                294                 :     else
 2404 peter_e                   295 GIC         299 :         result = value;
 9496 scrappy                   296 ECB             : 
                                297                 : #ifdef CASHDEBUG
                                298                 :     printf("cashin- result is " INT64_FORMAT "\n", result);
                                299                 : #endif
                                300                 : 
 8284 tgl                       301 GIC         796 :     PG_RETURN_CASH(result);
 8284 tgl                       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
 8284 tgl                       310 GIC         613 : cash_out(PG_FUNCTION_ARGS)
 9496 scrappy                   311 ECB             : {
 8284 tgl                       312 GIC         613 :     Cash        value = PG_GETARG_CASH(0);
 9344 bruce                     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;
 8170 tgl                       326 GIC         613 :     struct lconv *lconvert = PGLC_localeconv();
 9319 lockhart                  327 ECB             : 
                                328                 :     /* see comments about frac_digits in cash_in() */
 8177 tgl                       329 GIC         613 :     points = lconvert->frac_digits;
 8177 tgl                       330 CBC         613 :     if (points < 0 || points > 10)
                                331             613 :         points = 2;             /* best guess in this case, I think */
 8177 tgl                       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                 :      */
 9319 lockhart                  337 GIC         613 :     mon_group = *lconvert->mon_grouping;
 8177 tgl                       338 CBC         613 :     if (mon_group <= 0 || mon_group > 6)
                                339             613 :         mon_group = 3;
 8177 tgl                       340 ECB             : 
                                341                 :     /* we restrict dsymbol to be a single byte, but not the other symbols */
 4180 tgl                       342 GIC         613 :     if (*lconvert->mon_decimal_point != '\0' &&
 4180 tgl                       343 LBC           0 :         lconvert->mon_decimal_point[1] == '\0')
 4180 tgl                       344 UBC           0 :         dsymbol = *lconvert->mon_decimal_point;
 4180 tgl                       345 EUB             :     else
 4180 tgl                       346 GIC         613 :         dsymbol = '.';
 4180 tgl                       347 CBC         613 :     if (*lconvert->mon_thousands_sep != '\0')
 4180 tgl                       348 LBC           0 :         ssymbol = lconvert->mon_thousands_sep;
 2118 tgl                       349 EUB             :     else                        /* ssymbol should not equal dsymbol */
 4180 tgl                       350 GIC         613 :         ssymbol = (dsymbol != ',') ? "," : ".";
 4180 tgl                       351 CBC         613 :     csymbol = (*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$";
 9345 bruce                     352 ECB             : 
 9339 bruce                     353 GIC         613 :     if (value < 0)
 9345 bruce                     354 ECB             :     {
                                355                 :         /* make the amount positive for digit-reconstruction loop */
 7719 tgl                       356 GIC          43 :         value = -value;
 4179 tgl                       357 ECB             :         /* set up formatting data */
 4179 tgl                       358 GIC          43 :         signsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";
 4179 tgl                       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;
 4179 tgl                       362 ECB             :     }
                                363                 :     else
                                364                 :     {
 4179 tgl                       365 GIC         570 :         signsymbol = lconvert->positive_sign;
 4179 tgl                       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;
 9345 bruce                     369 ECB             :     }
                                370                 : 
                                371                 :     /* we build the digits+decimal-point+sep string right-to-left in buf[] */
 4180 tgl                       372 GIC         613 :     bufptr = buf + sizeof(buf) - 1;
 4180 tgl                       373 CBC         613 :     *bufptr = '\0';
 9345 bruce                     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                 :      */
 4180 tgl                       381 GIC         613 :     digit_pos = points;
 4180 tgl                       382 ECB             :     do
                                383                 :     {
 4180 tgl                       384 GIC        3689 :         if (points && digit_pos == 0)
 4180 tgl                       385 ECB             :         {
                                386                 :             /* insert decimal point, but not if value cannot be fractional */
 4180 tgl                       387 GIC         613 :             *(--bufptr) = dsymbol;
 4180 tgl                       388 ECB             :         }
 4179 tgl                       389 GIC        3076 :         else if (digit_pos < 0 && (digit_pos % mon_group) == 0)
 4180 tgl                       390 ECB             :         {
                                391                 :             /* insert thousands sep, but only to left of radix point */
 4180 tgl                       392 GIC         513 :             bufptr -= strlen(ssymbol);
 4180 tgl                       393 CBC         513 :             memcpy(bufptr, ssymbol, strlen(ssymbol));
 4180 tgl                       394 ECB             :         }
                                395                 : 
 4180 tgl                       396 GIC        3689 :         *(--bufptr) = ((uint64) value % 10) + '0';
 5940 darcy                     397 CBC        3689 :         value = ((uint64) value) / 10;
 4180 tgl                       398            3689 :         digit_pos--;
                                399            3689 :     } while (value || digit_pos >= 0);
 9345 bruce                     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                 :      */
 4179 tgl                       425 GIC         613 :     switch (sign_posn)
 9345 bruce                     426 ECB             :     {
 4179 tgl                       427 UIC           0 :         case 0:
 4179 tgl                       428 UBC           0 :             if (cs_precedes)
 3465 peter_e                   429               0 :                 result = psprintf("(%s%s%s)",
 3260 bruce                     430 EUB             :                                   csymbol,
                                431                 :                                   (sep_by_space == 1) ? " " : "",
                                432                 :                                   bufptr);
                                433                 :             else
 3465 peter_e                   434 UIC           0 :                 result = psprintf("(%s%s%s)",
 3260 bruce                     435 EUB             :                                   bufptr,
                                436                 :                                   (sep_by_space == 1) ? " " : "",
                                437                 :                                   csymbol);
 4179 tgl                       438 UIC           0 :             break;
 4179 tgl                       439 GBC         613 :         case 1:
 4179 tgl                       440 ECB             :         default:
 4179 tgl                       441 GIC         613 :             if (cs_precedes)
 3465 peter_e                   442 CBC         613 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     443 ECB             :                                   signsymbol,
                                444                 :                                   (sep_by_space == 2) ? " " : "",
                                445                 :                                   csymbol,
                                446                 :                                   (sep_by_space == 1) ? " " : "",
                                447                 :                                   bufptr);
                                448                 :             else
 3465 peter_e                   449 UIC           0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     450 EUB             :                                   signsymbol,
                                451                 :                                   (sep_by_space == 2) ? " " : "",
                                452                 :                                   bufptr,
                                453                 :                                   (sep_by_space == 1) ? " " : "",
                                454                 :                                   csymbol);
 4179 tgl                       455 GIC         613 :             break;
 4179 tgl                       456 LBC           0 :         case 2:
 4179 tgl                       457 UBC           0 :             if (cs_precedes)
 3465 peter_e                   458               0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     459 EUB             :                                   csymbol,
                                460                 :                                   (sep_by_space == 1) ? " " : "",
                                461                 :                                   bufptr,
                                462                 :                                   (sep_by_space == 2) ? " " : "",
                                463                 :                                   signsymbol);
                                464                 :             else
 3465 peter_e                   465 UIC           0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     466 EUB             :                                   bufptr,
                                467                 :                                   (sep_by_space == 1) ? " " : "",
                                468                 :                                   csymbol,
                                469                 :                                   (sep_by_space == 2) ? " " : "",
                                470                 :                                   signsymbol);
 4179 tgl                       471 UIC           0 :             break;
 4179 tgl                       472 UBC           0 :         case 3:
                                473               0 :             if (cs_precedes)
 3465 peter_e                   474               0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     475 EUB             :                                   signsymbol,
                                476                 :                                   (sep_by_space == 2) ? " " : "",
                                477                 :                                   csymbol,
                                478                 :                                   (sep_by_space == 1) ? " " : "",
                                479                 :                                   bufptr);
                                480                 :             else
 3465 peter_e                   481 UIC           0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     482 EUB             :                                   bufptr,
                                483                 :                                   (sep_by_space == 1) ? " " : "",
                                484                 :                                   signsymbol,
                                485                 :                                   (sep_by_space == 2) ? " " : "",
                                486                 :                                   csymbol);
 4179 tgl                       487 UIC           0 :             break;
 4179 tgl                       488 UBC           0 :         case 4:
                                489               0 :             if (cs_precedes)
 3465 peter_e                   490               0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     491 EUB             :                                   csymbol,
                                492                 :                                   (sep_by_space == 2) ? " " : "",
                                493                 :                                   signsymbol,
                                494                 :                                   (sep_by_space == 1) ? " " : "",
                                495                 :                                   bufptr);
                                496                 :             else
 3465 peter_e                   497 UIC           0 :                 result = psprintf("%s%s%s%s%s",
 3260 bruce                     498 EUB             :                                   bufptr,
                                499                 :                                   (sep_by_space == 1) ? " " : "",
                                500                 :                                   csymbol,
                                501                 :                                   (sep_by_space == 2) ? " " : "",
                                502                 :                                   signsymbol);
 4179 tgl                       503 UIC           0 :             break;
 9345 bruce                     504 EUB             :     }
                                505                 : 
 8284 tgl                       506 GIC         613 :     PG_RETURN_CSTRING(result);
 8284 tgl                       507 ECB             : }
                                508                 : 
                                509                 : /*
                                510                 :  *      cash_recv           - converts external binary format to cash
                                511                 :  */
                                512                 : Datum
 7271 tgl                       513 UIC           0 : cash_recv(PG_FUNCTION_ARGS)
 7271 tgl                       514 EUB             : {
 7271 tgl                       515 UIC           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
 7271 tgl                       516 EUB             : 
 5710 tgl                       517 UIC           0 :     PG_RETURN_CASH((Cash) pq_getmsgint64(buf));
 7271 tgl                       518 EUB             : }
                                519                 : 
                                520                 : /*
                                521                 :  *      cash_send           - converts cash to binary format
                                522                 :  */
                                523                 : Datum
 7271 tgl                       524 UIC           0 : cash_send(PG_FUNCTION_ARGS)
 7271 tgl                       525 EUB             : {
 7271 tgl                       526 UIC           0 :     Cash        arg1 = PG_GETARG_CASH(0);
 7271 tgl                       527 EUB             :     StringInfoData buf;
                                528                 : 
 7271 tgl                       529 UIC           0 :     pq_begintypsend(&buf);
 5710 tgl                       530 UBC           0 :     pq_sendint64(&buf, arg1);
 7271                           531               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 7271 tgl                       532 EUB             : }
                                533                 : 
                                534                 : /*
                                535                 :  * Comparison functions
                                536                 :  */
                                537                 : 
                                538                 : Datum
 8284 tgl                       539 GIC         577 : cash_eq(PG_FUNCTION_ARGS)
 9490 scrappy                   540 ECB             : {
 8284 tgl                       541 GIC         577 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       542 CBC         577 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   543 ECB             : 
 8284 tgl                       544 GIC         577 :     PG_RETURN_BOOL(c1 == c2);
 8284 tgl                       545 ECB             : }
                                546                 : 
                                547                 : Datum
 8284 tgl                       548 GIC          33 : cash_ne(PG_FUNCTION_ARGS)
 9490 scrappy                   549 ECB             : {
 8284 tgl                       550 GIC          33 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       551 CBC          33 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   552 ECB             : 
 8284 tgl                       553 GIC          33 :     PG_RETURN_BOOL(c1 != c2);
 8284 tgl                       554 ECB             : }
                                555                 : 
                                556                 : Datum
 8284 tgl                       557 GIC         549 : cash_lt(PG_FUNCTION_ARGS)
 9496 scrappy                   558 ECB             : {
 8284 tgl                       559 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       560 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   561 ECB             : 
 8284 tgl                       562 GIC         549 :     PG_RETURN_BOOL(c1 < c2);
 8284 tgl                       563 ECB             : }
                                564                 : 
                                565                 : Datum
 8284 tgl                       566 GIC         549 : cash_le(PG_FUNCTION_ARGS)
 9496 scrappy                   567 ECB             : {
 8284 tgl                       568 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       569 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   570 ECB             : 
 8284 tgl                       571 GIC         549 :     PG_RETURN_BOOL(c1 <= c2);
 8284 tgl                       572 ECB             : }
                                573                 : 
                                574                 : Datum
 8284 tgl                       575 GIC         549 : cash_gt(PG_FUNCTION_ARGS)
 9490 scrappy                   576 ECB             : {
 8284 tgl                       577 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       578 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   579 ECB             : 
 8284 tgl                       580 GIC         549 :     PG_RETURN_BOOL(c1 > c2);
 8284 tgl                       581 ECB             : }
                                582                 : 
                                583                 : Datum
 8284 tgl                       584 GIC         549 : cash_ge(PG_FUNCTION_ARGS)
 9496 scrappy                   585 ECB             : {
 8284 tgl                       586 GIC         549 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       587 CBC         549 :     Cash        c2 = PG_GETARG_CASH(1);
 9496 scrappy                   588 ECB             : 
 8284 tgl                       589 GIC         549 :     PG_RETURN_BOOL(c1 >= c2);
 8284 tgl                       590 ECB             : }
                                591                 : 
                                592                 : Datum
 7175 tgl                       593 GIC         731 : cash_cmp(PG_FUNCTION_ARGS)
 7175 tgl                       594 ECB             : {
 7175 tgl                       595 GIC         731 :     Cash        c1 = PG_GETARG_CASH(0);
 7175 tgl                       596 CBC         731 :     Cash        c2 = PG_GETARG_CASH(1);
 7175 tgl                       597 ECB             : 
 7175 tgl                       598 GIC         731 :     if (c1 > c2)
 7175 tgl                       599 CBC         585 :         PG_RETURN_INT32(1);
                                600             146 :     else if (c1 == c2)
                                601              16 :         PG_RETURN_INT32(0);
 7175 tgl                       602 ECB             :     else
 7175 tgl                       603 GIC         130 :         PG_RETURN_INT32(-1);
 7175 tgl                       604 ECB             : }
                                605                 : 
                                606                 : 
                                607                 : /* cash_pl()
                                608                 :  * Add two cash values.
                                609                 :  */
                                610                 : Datum
 8284 tgl                       611 GIC          21 : cash_pl(PG_FUNCTION_ARGS)
 9490 scrappy                   612 ECB             : {
 8284 tgl                       613 GIC          21 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       614 CBC          21 :     Cash        c2 = PG_GETARG_CASH(1);
 8284 tgl                       615 ECB             :     Cash        result;
                                616                 : 
 8284 tgl                       617 GIC          21 :     result = c1 + c2;
 9490 scrappy                   618 ECB             : 
 8284 tgl                       619 GIC          21 :     PG_RETURN_CASH(result);
 8284 tgl                       620 ECB             : }
                                621                 : 
                                622                 : 
                                623                 : /* cash_mi()
                                624                 :  * Subtract two cash values.
                                625                 :  */
                                626                 : Datum
 8284 tgl                       627 GIC           6 : cash_mi(PG_FUNCTION_ARGS)
 9490 scrappy                   628 ECB             : {
 8284 tgl                       629 GIC           6 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       630 CBC           6 :     Cash        c2 = PG_GETARG_CASH(1);
 8284 tgl                       631 ECB             :     Cash        result;
                                632                 : 
 8284 tgl                       633 GIC           6 :     result = c1 - c2;
 9496 scrappy                   634 ECB             : 
 8284 tgl                       635 GIC           6 :     PG_RETURN_CASH(result);
 8284 tgl                       636 ECB             : }
                                637                 : 
                                638                 : 
                                639                 : /* cash_div_cash()
                                640                 :  * Divide cash by cash, returning float8.
                                641                 :  */
                                642                 : Datum
 4650 tgl                       643 GIC           3 : cash_div_cash(PG_FUNCTION_ARGS)
 4650 tgl                       644 ECB             : {
 4650 tgl                       645 GIC           3 :     Cash        dividend = PG_GETARG_CASH(0);
 4650 tgl                       646 CBC           3 :     Cash        divisor = PG_GETARG_CASH(1);
 4650 tgl                       647 ECB             :     float8      quotient;
                                648                 : 
 4650 tgl                       649 GIC           3 :     if (divisor == 0)
 4650 tgl                       650 LBC           0 :         ereport(ERROR,
 4650 tgl                       651 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                652                 :                  errmsg("division by zero")));
                                653                 : 
 4650 tgl                       654 GIC           3 :     quotient = (float8) dividend / (float8) divisor;
 4650 tgl                       655 CBC           3 :     PG_RETURN_FLOAT8(quotient);
 4650 tgl                       656 ECB             : }
                                657                 : 
                                658                 : 
                                659                 : /* cash_mul_flt8()
                                660                 :  * Multiply cash by float8.
                                661                 :  */
                                662                 : Datum
 8286 tgl                       663 GIC           3 : cash_mul_flt8(PG_FUNCTION_ARGS)
 9490 scrappy                   664 ECB             : {
 8286 tgl                       665 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
 8286 tgl                       666 CBC           3 :     float8      f = PG_GETARG_FLOAT8(1);
 8286 tgl                       667 ECB             :     Cash        result;
                                668                 : 
 2149 tgl                       669 GIC           3 :     result = rint(c * f);
 8286 tgl                       670 CBC           3 :     PG_RETURN_CASH(result);
 8286 tgl                       671 ECB             : }
                                672                 : 
                                673                 : 
                                674                 : /* flt8_mul_cash()
                                675                 :  * Multiply float8 by cash.
                                676                 :  */
                                677                 : Datum
 8286 tgl                       678 GIC           3 : flt8_mul_cash(PG_FUNCTION_ARGS)
 9332 lockhart                  679 ECB             : {
 8286 tgl                       680 GIC           3 :     float8      f = PG_GETARG_FLOAT8(0);
 8286 tgl                       681 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
 8286 tgl                       682 ECB             :     Cash        result;
                                683                 : 
 2149 tgl                       684 GIC           3 :     result = rint(f * c);
 8286 tgl                       685 CBC           3 :     PG_RETURN_CASH(result);
 8286 tgl                       686 ECB             : }
                                687                 : 
                                688                 : 
                                689                 : /* cash_div_flt8()
                                690                 :  * Divide cash by float8.
                                691                 :  */
                                692                 : Datum
 8286 tgl                       693 GIC           6 : cash_div_flt8(PG_FUNCTION_ARGS)
 9490 scrappy                   694 ECB             : {
 8286 tgl                       695 GIC           6 :     Cash        c = PG_GETARG_CASH(0);
 8286 tgl                       696 CBC           6 :     float8      f = PG_GETARG_FLOAT8(1);
 8286 tgl                       697 ECB             :     Cash        result;
                                698                 : 
 8286 tgl                       699 GIC           6 :     if (f == 0.0)
 7196 tgl                       700 LBC           0 :         ereport(ERROR,
 7196 tgl                       701 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                702                 :                  errmsg("division by zero")));
                                703                 : 
 8286 tgl                       704 GIC           6 :     result = rint(c / f);
 8286 tgl                       705 CBC           6 :     PG_RETURN_CASH(result);
 8286 tgl                       706 ECB             : }
                                707                 : 
                                708                 : 
                                709                 : /* cash_mul_flt4()
                                710                 :  * Multiply cash by float4.
                                711                 :  */
                                712                 : Datum
 8286 tgl                       713 GIC           3 : cash_mul_flt4(PG_FUNCTION_ARGS)
 9332 lockhart                  714 ECB             : {
 8286 tgl                       715 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
 8286 tgl                       716 CBC           3 :     float4      f = PG_GETARG_FLOAT4(1);
 8286 tgl                       717 ECB             :     Cash        result;
                                718                 : 
 2149 tgl                       719 GIC           3 :     result = rint(c * (float8) f);
 8286 tgl                       720 CBC           3 :     PG_RETURN_CASH(result);
 8286 tgl                       721 ECB             : }
                                722                 : 
                                723                 : 
                                724                 : /* flt4_mul_cash()
                                725                 :  * Multiply float4 by cash.
                                726                 :  */
                                727                 : Datum
 8286 tgl                       728 GIC           3 : flt4_mul_cash(PG_FUNCTION_ARGS)
 9332 lockhart                  729 ECB             : {
 8286 tgl                       730 GIC           3 :     float4      f = PG_GETARG_FLOAT4(0);
 8286 tgl                       731 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
 8286 tgl                       732 ECB             :     Cash        result;
                                733                 : 
 2149 tgl                       734 GIC           3 :     result = rint((float8) f * c);
 8286 tgl                       735 CBC           3 :     PG_RETURN_CASH(result);
 8286 tgl                       736 ECB             : }
                                737                 : 
                                738                 : 
                                739                 : /* cash_div_flt4()
                                740                 :  * Divide cash by float4.
                                741                 :  *
                                742                 :  */
                                743                 : Datum
 8286 tgl                       744 GIC           6 : cash_div_flt4(PG_FUNCTION_ARGS)
 9332 lockhart                  745 ECB             : {
 8286 tgl                       746 GIC           6 :     Cash        c = PG_GETARG_CASH(0);
 8286 tgl                       747 CBC           6 :     float4      f = PG_GETARG_FLOAT4(1);
 8286 tgl                       748 ECB             :     Cash        result;
                                749                 : 
 8286 tgl                       750 GIC           6 :     if (f == 0.0)
 7196 tgl                       751 LBC           0 :         ereport(ERROR,
 7196 tgl                       752 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                753                 :                  errmsg("division by zero")));
                                754                 : 
 2149 tgl                       755 GIC           6 :     result = rint(c / (float8) f);
 8286 tgl                       756 CBC           6 :     PG_RETURN_CASH(result);
 8286 tgl                       757 ECB             : }
                                758                 : 
                                759                 : 
                                760                 : /* cash_mul_int8()
                                761                 :  * Multiply cash by int8.
                                762                 :  */
                                763                 : Datum
 5940 darcy                     764 GIC           3 : cash_mul_int8(PG_FUNCTION_ARGS)
 5940 darcy                     765 ECB             : {
 5940 darcy                     766 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
 5940 darcy                     767 CBC           3 :     int64       i = PG_GETARG_INT64(1);
 5940 darcy                     768 ECB             :     Cash        result;
                                769                 : 
 5940 darcy                     770 GIC           3 :     result = c * i;
 5940 darcy                     771 CBC           3 :     PG_RETURN_CASH(result);
 5940 darcy                     772 ECB             : }
                                773                 : 
                                774                 : 
                                775                 : /* int8_mul_cash()
                                776                 :  * Multiply int8 by cash.
                                777                 :  */
                                778                 : Datum
 5940 darcy                     779 GIC           3 : int8_mul_cash(PG_FUNCTION_ARGS)
 5940 darcy                     780 ECB             : {
 5940 darcy                     781 GIC           3 :     int64       i = PG_GETARG_INT64(0);
 5940 darcy                     782 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
 5940 darcy                     783 ECB             :     Cash        result;
                                784                 : 
 5940 darcy                     785 GIC           3 :     result = i * c;
 5940 darcy                     786 CBC           3 :     PG_RETURN_CASH(result);
 5940 darcy                     787 ECB             : }
                                788                 : 
                                789                 : /* cash_div_int8()
                                790                 :  * Divide cash by 8-byte integer.
                                791                 :  */
                                792                 : Datum
 5940 darcy                     793 GIC           9 : cash_div_int8(PG_FUNCTION_ARGS)
 5940 darcy                     794 ECB             : {
 5940 darcy                     795 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
 5940 darcy                     796 CBC           9 :     int64       i = PG_GETARG_INT64(1);
 5940 darcy                     797 ECB             :     Cash        result;
                                798                 : 
 5940 darcy                     799 GIC           9 :     if (i == 0)
 5940 darcy                     800 LBC           0 :         ereport(ERROR,
 5940 darcy                     801 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                802                 :                  errmsg("division by zero")));
                                803                 : 
 2149 tgl                       804 GIC           9 :     result = c / i;
 5940 darcy                     805 ECB             : 
 5940 darcy                     806 GIC           9 :     PG_RETURN_CASH(result);
 5940 darcy                     807 ECB             : }
                                808                 : 
                                809                 : 
                                810                 : /* cash_mul_int4()
                                811                 :  * Multiply cash by int4.
                                812                 :  */
                                813                 : Datum
 8335 tgl                       814 GIC           3 : cash_mul_int4(PG_FUNCTION_ARGS)
 9332 lockhart                  815 ECB             : {
 8335 tgl                       816 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
 5710 tgl                       817 CBC           3 :     int32       i = PG_GETARG_INT32(1);
 8335 tgl                       818 ECB             :     Cash        result;
                                819                 : 
 8335 tgl                       820 GIC           3 :     result = c * i;
 8335 tgl                       821 CBC           3 :     PG_RETURN_CASH(result);
 8335 tgl                       822 ECB             : }
                                823                 : 
                                824                 : 
                                825                 : /* int4_mul_cash()
                                826                 :  * Multiply int4 by cash.
                                827                 :  */
                                828                 : Datum
 8335 tgl                       829 GIC           3 : int4_mul_cash(PG_FUNCTION_ARGS)
 9332 lockhart                  830 ECB             : {
 8335 tgl                       831 GIC           3 :     int32       i = PG_GETARG_INT32(0);
 8335 tgl                       832 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
 8335 tgl                       833 ECB             :     Cash        result;
                                834                 : 
 8335 tgl                       835 GIC           3 :     result = i * c;
 8335 tgl                       836 CBC           3 :     PG_RETURN_CASH(result);
 8335 tgl                       837 ECB             : }
                                838                 : 
                                839                 : 
                                840                 : /* cash_div_int4()
                                841                 :  * Divide cash by 4-byte integer.
                                842                 :  *
                                843                 :  */
                                844                 : Datum
 8335 tgl                       845 GIC           9 : cash_div_int4(PG_FUNCTION_ARGS)
 9332 lockhart                  846 ECB             : {
 8335 tgl                       847 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
 5710 tgl                       848 CBC           9 :     int32       i = PG_GETARG_INT32(1);
 8335 tgl                       849 ECB             :     Cash        result;
                                850                 : 
 9332 lockhart                  851 GIC           9 :     if (i == 0)
 7196 tgl                       852 LBC           0 :         ereport(ERROR,
 7196 tgl                       853 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                854                 :                  errmsg("division by zero")));
                                855                 : 
 2149 tgl                       856 GIC           9 :     result = c / i;
 9332 lockhart                  857 ECB             : 
 8335 tgl                       858 GIC           9 :     PG_RETURN_CASH(result);
 8335 tgl                       859 ECB             : }
                                860                 : 
                                861                 : 
                                862                 : /* cash_mul_int2()
                                863                 :  * Multiply cash by int2.
                                864                 :  */
                                865                 : Datum
 8343 tgl                       866 GIC           3 : cash_mul_int2(PG_FUNCTION_ARGS)
 9332 lockhart                  867 ECB             : {
 8343 tgl                       868 GIC           3 :     Cash        c = PG_GETARG_CASH(0);
 8343 tgl                       869 CBC           3 :     int16       s = PG_GETARG_INT16(1);
 8343 tgl                       870 ECB             :     Cash        result;
                                871                 : 
 8343 tgl                       872 GIC           3 :     result = c * s;
 8343 tgl                       873 CBC           3 :     PG_RETURN_CASH(result);
 8343 tgl                       874 ECB             : }
                                875                 : 
                                876                 : /* int2_mul_cash()
                                877                 :  * Multiply int2 by cash.
                                878                 :  */
                                879                 : Datum
 8343 tgl                       880 GIC           3 : int2_mul_cash(PG_FUNCTION_ARGS)
 9332 lockhart                  881 ECB             : {
 8343 tgl                       882 GIC           3 :     int16       s = PG_GETARG_INT16(0);
 8343 tgl                       883 CBC           3 :     Cash        c = PG_GETARG_CASH(1);
 8343 tgl                       884 ECB             :     Cash        result;
                                885                 : 
 8343 tgl                       886 GIC           3 :     result = s * c;
 8343 tgl                       887 CBC           3 :     PG_RETURN_CASH(result);
 8343 tgl                       888 ECB             : }
                                889                 : 
                                890                 : /* cash_div_int2()
                                891                 :  * Divide cash by int2.
                                892                 :  *
                                893                 :  */
                                894                 : Datum
 8343 tgl                       895 GIC           9 : cash_div_int2(PG_FUNCTION_ARGS)
 9332 lockhart                  896 ECB             : {
 8343 tgl                       897 GIC           9 :     Cash        c = PG_GETARG_CASH(0);
 8343 tgl                       898 CBC           9 :     int16       s = PG_GETARG_INT16(1);
 8343 tgl                       899 ECB             :     Cash        result;
                                900                 : 
 9332 lockhart                  901 GIC           9 :     if (s == 0)
 7196 tgl                       902 LBC           0 :         ereport(ERROR,
 7196 tgl                       903 EUB             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
                                904                 :                  errmsg("division by zero")));
                                905                 : 
 2149 tgl                       906 GIC           9 :     result = c / s;
 8343 tgl                       907 CBC           9 :     PG_RETURN_CASH(result);
 8343 tgl                       908 ECB             : }
                                909                 : 
                                910                 : /* cashlarger()
                                911                 :  * Return larger of two cash values.
                                912                 :  */
                                913                 : Datum
 8284 tgl                       914 GIC           3 : cashlarger(PG_FUNCTION_ARGS)
 9490 scrappy                   915 ECB             : {
 8284 tgl                       916 GIC           3 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       917 CBC           3 :     Cash        c2 = PG_GETARG_CASH(1);
 8284 tgl                       918 ECB             :     Cash        result;
                                919                 : 
 8284 tgl                       920 GIC           3 :     result = (c1 > c2) ? c1 : c2;
 9490 scrappy                   921 ECB             : 
 8284 tgl                       922 GIC           3 :     PG_RETURN_CASH(result);
 8284 tgl                       923 ECB             : }
                                924                 : 
                                925                 : /* cashsmaller()
                                926                 :  * Return smaller of two cash values.
                                927                 :  */
                                928                 : Datum
 8284 tgl                       929 GIC           3 : cashsmaller(PG_FUNCTION_ARGS)
 9490 scrappy                   930 ECB             : {
 8284 tgl                       931 GIC           3 :     Cash        c1 = PG_GETARG_CASH(0);
 8284 tgl                       932 CBC           3 :     Cash        c2 = PG_GETARG_CASH(1);
 8284 tgl                       933 ECB             :     Cash        result;
                                934                 : 
 8284 tgl                       935 GIC           3 :     result = (c1 < c2) ? c1 : c2;
 9490 scrappy                   936 ECB             : 
 8284 tgl                       937 GIC           3 :     PG_RETURN_CASH(result);
 8284 tgl                       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
 8311 bruce                     945 GIC        6006 : cash_words(PG_FUNCTION_ARGS)
 9490 scrappy                   946 ECB             : {
 8312 tgl                       947 GIC        6006 :     Cash        value = PG_GETARG_CASH(0);
 5624 bruce                     948 ECB             :     uint64      val;
                                949                 :     char        buf[256];
 9344 bruce                     950 GIC        6006 :     char       *p = buf;
 9344 bruce                     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 */
 8312 tgl                       960 GIC        6006 :     if (value < 0)
 9345 bruce                     961 ECB             :     {
 8312 tgl                       962 UIC           0 :         value = -value;
 9345 bruce                     963 UBC           0 :         strcpy(buf, "minus ");
                                964               0 :         p += 6;
 9345 bruce                     965 EUB             :     }
                                966                 :     else
 8312 tgl                       967 GIC        6006 :         buf[0] = '\0';
 9345 bruce                     968 ECB             : 
                                969                 :     /* Now treat as unsigned, to avoid trouble at INT_MIN */
 5940 darcy                     970 GIC        6006 :     val = (uint64) value;
 7719 tgl                       971 ECB             : 
 5050 bruce                     972 GIC        6006 :     m0 = val % INT64CONST(100); /* cents */
 2118 tgl                       973 CBC        6006 :     m1 = (val / INT64CONST(100)) % 1000;    /* hundreds */
                                974            6006 :     m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
 5050 bruce                     975            6006 :     m3 = (val / INT64CONST(100000000)) % 1000;  /* millions */
 2118 tgl                       976            6006 :     m4 = (val / INT64CONST(100000000000)) % 1000;   /* billions */
 5417                           977            6006 :     m5 = (val / INT64CONST(100000000000000)) % 1000;    /* trillions */
 5050 bruce                     978            6006 :     m6 = (val / INT64CONST(100000000000000000)) % 1000; /* quadrillions */
 5940 darcy                     979 ECB             : 
 5940 darcy                     980 GIC        6006 :     if (m6)
 5940 darcy                     981 ECB             :     {
 5940 darcy                     982 UIC           0 :         strcat(buf, num_word(m6));
 5940 darcy                     983 UBC           0 :         strcat(buf, " quadrillion ");
 5940 darcy                     984 EUB             :     }
                                985                 : 
 5940 darcy                     986 GIC        6006 :     if (m5)
 5940 darcy                     987 ECB             :     {
 5940 darcy                     988 UIC           0 :         strcat(buf, num_word(m5));
 5940 darcy                     989 UBC           0 :         strcat(buf, " trillion ");
 5940 darcy                     990 EUB             :     }
                                991                 : 
 5940 darcy                     992 GIC        6006 :     if (m4)
 5940 darcy                     993 ECB             :     {
 5940 darcy                     994 UIC           0 :         strcat(buf, num_word(m4));
 5940 darcy                     995 UBC           0 :         strcat(buf, " billion ");
 5940 darcy                     996 EUB             :     }
                                997                 : 
 9345 bruce                     998 GIC        6006 :     if (m3)
 9345 bruce                     999 ECB             :     {
 9345 bruce                    1000 UIC           0 :         strcat(buf, num_word(m3));
 9345 bruce                    1001 UBC           0 :         strcat(buf, " million ");
 9345 bruce                    1002 EUB             :     }
                               1003                 : 
 9345 bruce                    1004 GIC        6006 :     if (m2)
 9345 bruce                    1005 ECB             :     {
 9345 bruce                    1006 UIC           0 :         strcat(buf, num_word(m2));
 9345 bruce                    1007 UBC           0 :         strcat(buf, " thousand ");
 9345 bruce                    1008 EUB             :     }
                               1009                 : 
 9345 bruce                    1010 GIC        6006 :     if (m1)
 9345 bruce                    1011 CBC        5580 :         strcat(buf, num_word(m1));
 9345 bruce                    1012 ECB             : 
 9345 bruce                    1013 GIC        6006 :     if (!*p)
 9345 bruce                    1014 CBC         426 :         strcat(buf, "zero");
 9345 bruce                    1015 ECB             : 
 7719 tgl                      1016 GIC        6006 :     strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
 9345 bruce                    1017 CBC        6006 :     strcat(buf, num_word(m0));
                               1018            6006 :     strcat(buf, m0 == 1 ? " cent" : " cents");
 8945 bruce                    1019 ECB             : 
                               1020                 :     /* capitalize output */
 6911 tgl                      1021 GIC        6006 :     buf[0] = pg_toupper((unsigned char) buf[0]);
 8945 bruce                    1022 ECB             : 
                               1023                 :     /* return as text datum */
 5493 tgl                      1024 GIC        6006 :     PG_RETURN_TEXT_P(cstring_to_text(buf));
 8312 tgl                      1025 ECB             : }
                               1026                 : 
                               1027                 : 
                               1028                 : /* cash_numeric()
                               1029                 :  * Convert cash to numeric.
                               1030                 :  */
                               1031                 : Datum
 4650 tgl                      1032 GIC          12 : cash_numeric(PG_FUNCTION_ARGS)
 4650 tgl                      1033 ECB             : {
 4650 tgl                      1034 GIC          12 :     Cash        money = PG_GETARG_CASH(0);
 1353 tgl                      1035 ECB             :     Datum       result;
                               1036                 :     int         fpoint;
 4650 tgl                      1037 GIC          12 :     struct lconv *lconvert = PGLC_localeconv();
 4650 tgl                      1038 ECB             : 
                               1039                 :     /* see comments about frac_digits in cash_in() */
 4650 tgl                      1040 GIC          12 :     fpoint = lconvert->frac_digits;
 4650 tgl                      1041 CBC          12 :     if (fpoint < 0 || fpoint > 10)
                               1042              12 :         fpoint = 2;
 4650 tgl                      1043 ECB             : 
                               1044                 :     /* convert the integral money value to numeric */
  942 peter                    1045 GIC          12 :     result = NumericGetDatum(int64_to_numeric(money));
 4650 tgl                      1046 ECB             : 
                               1047                 :     /* scale appropriately, if needed */
 1353 tgl                      1048 GIC          12 :     if (fpoint > 0)
 1353 tgl                      1049 ECB             :     {
                               1050                 :         int64       scale;
                               1051                 :         int         i;
                               1052                 :         Datum       numeric_scale;
                               1053                 :         Datum       quotient;
                               1054                 : 
                               1055                 :         /* compute required scale factor */
 1353 tgl                      1056 GIC          12 :         scale = 1;
 1353 tgl                      1057 CBC          36 :         for (i = 0; i < fpoint; i++)
                               1058              24 :             scale *= 10;
  942 peter                    1059              12 :         numeric_scale = NumericGetDatum(int64_to_numeric(scale));
 1353 tgl                      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                 :          */
 1353 tgl                      1068 GIC          12 :         numeric_scale = DirectFunctionCall2(numeric_round,
 1353 tgl                      1069 ECB             :                                             numeric_scale,
                               1070                 :                                             Int32GetDatum(fpoint));
                               1071                 : 
                               1072                 :         /* Now we can safely divide ... */
 1353 tgl                      1073 GIC          12 :         quotient = DirectFunctionCall2(numeric_div, result, numeric_scale);
 4650 tgl                      1074 ECB             : 
                               1075                 :         /* ... and forcibly round to exactly the intended number of digits */
 1353 tgl                      1076 GIC          12 :         result = DirectFunctionCall2(numeric_round,
 1353 tgl                      1077 ECB             :                                      quotient,
                               1078                 :                                      Int32GetDatum(fpoint));
                               1079                 :     }
                               1080                 : 
 1353 tgl                      1081 GIC          12 :     PG_RETURN_DATUM(result);
 4650 tgl                      1082 ECB             : }
                               1083                 : 
                               1084                 : /* numeric_cash()
                               1085                 :  * Convert numeric to cash.
                               1086                 :  */
                               1087                 : Datum
 4650 tgl                      1088 GIC           6 : numeric_cash(PG_FUNCTION_ARGS)
 4650 tgl                      1089 ECB             : {
 4650 tgl                      1090 GIC           6 :     Datum       amount = PG_GETARG_DATUM(0);
 4650 tgl                      1091 ECB             :     Cash        result;
                               1092                 :     int         fpoint;
                               1093                 :     int64       scale;
                               1094                 :     int         i;
                               1095                 :     Datum       numeric_scale;
 4650 tgl                      1096 GIC           6 :     struct lconv *lconvert = PGLC_localeconv();
 4650 tgl                      1097 ECB             : 
                               1098                 :     /* see comments about frac_digits in cash_in() */
 4650 tgl                      1099 GIC           6 :     fpoint = lconvert->frac_digits;
 4650 tgl                      1100 CBC           6 :     if (fpoint < 0 || fpoint > 10)
                               1101               6 :         fpoint = 2;
 4650 tgl                      1102 ECB             : 
                               1103                 :     /* compute required scale factor */
 4650 tgl                      1104 GIC           6 :     scale = 1;
 4650 tgl                      1105 CBC          18 :     for (i = 0; i < fpoint; i++)
                               1106              12 :         scale *= 10;
 4650 tgl                      1107 ECB             : 
                               1108                 :     /* multiply the input amount by scale factor */
  942 peter                    1109 GIC           6 :     numeric_scale = NumericGetDatum(int64_to_numeric(scale));
 4650 tgl                      1110 CBC           6 :     amount = DirectFunctionCall2(numeric_mul, amount, numeric_scale);
 4650 tgl                      1111 ECB             : 
                               1112                 :     /* note that numeric_int8 will round to nearest integer for us */
 4650 tgl                      1113 GIC           6 :     result = DatumGetInt64(DirectFunctionCall1(numeric_int8, amount));
 4650 tgl                      1114 ECB             : 
 4650 tgl                      1115 GIC           6 :     PG_RETURN_CASH(result);
 4650 tgl                      1116 ECB             : }
                               1117                 : 
                               1118                 : /* int4_cash()
                               1119                 :  * Convert int4 (int) to cash
                               1120                 :  */
                               1121                 : Datum
 4387 rhaas                    1122 GIC        6072 : int4_cash(PG_FUNCTION_ARGS)
 4387 rhaas                    1123 ECB             : {
 4382 bruce                    1124 GIC        6072 :     int32       amount = PG_GETARG_INT32(0);
 4382 bruce                    1125 ECB             :     Cash        result;
                               1126                 :     int         fpoint;
                               1127                 :     int64       scale;
                               1128                 :     int         i;
 4387 rhaas                    1129 GIC        6072 :     struct lconv *lconvert = PGLC_localeconv();
 4387 rhaas                    1130 ECB             : 
                               1131                 :     /* see comments about frac_digits in cash_in() */
 4387 rhaas                    1132 GIC        6072 :     fpoint = lconvert->frac_digits;
 4387 rhaas                    1133 CBC        6072 :     if (fpoint < 0 || fpoint > 10)
                               1134            6072 :         fpoint = 2;
 4387 rhaas                    1135 ECB             : 
                               1136                 :     /* compute required scale factor */
 4387 rhaas                    1137 GIC        6072 :     scale = 1;
 4387 rhaas                    1138 CBC       18216 :     for (i = 0; i < fpoint; i++)
                               1139           12144 :         scale *= 10;
 4387 rhaas                    1140 ECB             : 
                               1141                 :     /* compute amount * scale, checking for overflow */
 4387 rhaas                    1142 GIC        6072 :     result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
 4382 bruce                    1143 ECB             :                                                Int64GetDatum(scale)));
                               1144                 : 
 4387 rhaas                    1145 GIC        6072 :     PG_RETURN_CASH(result);
 4387 rhaas                    1146 ECB             : }
                               1147                 : 
                               1148                 : /* int8_cash()
                               1149                 :  * Convert int8 (bigint) to cash
                               1150                 :  */
                               1151                 : Datum
 4387 rhaas                    1152 GIC          12 : int8_cash(PG_FUNCTION_ARGS)
 4387 rhaas                    1153 ECB             : {
 4382 bruce                    1154 GIC          12 :     int64       amount = PG_GETARG_INT64(0);
 4382 bruce                    1155 ECB             :     Cash        result;
                               1156                 :     int         fpoint;
                               1157                 :     int64       scale;
                               1158                 :     int         i;
 4387 rhaas                    1159 GIC          12 :     struct lconv *lconvert = PGLC_localeconv();
 4387 rhaas                    1160 ECB             : 
                               1161                 :     /* see comments about frac_digits in cash_in() */
 4387 rhaas                    1162 GIC          12 :     fpoint = lconvert->frac_digits;
 4387 rhaas                    1163 CBC          12 :     if (fpoint < 0 || fpoint > 10)
                               1164              12 :         fpoint = 2;
 4387 rhaas                    1165 ECB             : 
                               1166                 :     /* compute required scale factor */
 4387 rhaas                    1167 GIC          12 :     scale = 1;
 4387 rhaas                    1168 CBC          36 :     for (i = 0; i < fpoint; i++)
                               1169              24 :         scale *= 10;
 4387 rhaas                    1170 ECB             : 
                               1171                 :     /* compute amount * scale, checking for overflow */
 4387 rhaas                    1172 GIC          12 :     result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
 4382 bruce                    1173 ECB             :                                                Int64GetDatum(scale)));
                               1174                 : 
 4387 rhaas                    1175 GIC          12 :     PG_RETURN_CASH(result);
 4387 rhaas                    1176 ECB             : }
        

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