1997-04-09 10:36:21 +02:00
|
|
|
/*
|
1997-04-15 19:41:44 +02:00
|
|
|
* cash.c
|
|
|
|
* Written by D'Arcy J.M. Cain
|
2007-01-03 02:19:51 +01:00
|
|
|
* darcy@druid.net
|
|
|
|
* http://www.druid.net/darcy/
|
1997-04-15 19:41:44 +02:00
|
|
|
*
|
|
|
|
* Functions to allow input and output of money normally but store
|
2007-01-03 02:19:51 +01:00
|
|
|
* and handle it as 64 bit ints
|
1997-04-15 19:41:44 +02:00
|
|
|
*
|
|
|
|
* A slightly modified version of this file and a discussion of the
|
|
|
|
* workings can be found in the book "Software Solutions in C" by
|
2007-01-03 02:19:51 +01:00
|
|
|
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7 except that
|
|
|
|
* this version handles 64 bit numbers and so can hold values up to
|
|
|
|
* $92,233,720,368,547,758.07.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2007-08-21 05:56:07 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.73 2007/08/21 03:56:07 tgl Exp $
|
1997-04-15 19:41:44 +02:00
|
|
|
*/
|
|
|
|
|
2000-11-25 23:43:08 +01:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1997-04-15 19:41:44 +02:00
|
|
|
#include <limits.h>
|
|
|
|
#include <ctype.h>
|
2000-06-15 05:33:12 +02:00
|
|
|
#include <math.h>
|
1997-04-15 19:41:44 +02:00
|
|
|
#include <locale.h>
|
|
|
|
|
2003-05-13 20:03:08 +02:00
|
|
|
#include "libpq/pqformat.h"
|
1997-04-15 19:41:44 +02:00
|
|
|
#include "utils/cash.h"
|
2000-11-25 23:43:08 +01:00
|
|
|
#include "utils/pg_locale.h"
|
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
#define CASH_BUFSZ 36
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
#define TERMINATOR (CASH_BUFSZ - 1)
|
|
|
|
#define LAST_PAREN (TERMINATOR - 1)
|
|
|
|
#define LAST_DIGIT (LAST_PAREN - 1)
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
/*
|
|
|
|
* Cash is a pass-by-ref SQL type, so we must pass and return pointers.
|
|
|
|
* These macros and support routine hide the pass-by-refness.
|
|
|
|
*/
|
2000-07-06 07:48:31 +02:00
|
|
|
#define PG_GETARG_CASH(n) (* ((Cash *) PG_GETARG_POINTER(n)))
|
2000-06-05 09:29:25 +02:00
|
|
|
#define PG_RETURN_CASH(x) return CashGetDatum(x)
|
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* Private routines
|
|
|
|
************************************************************************/
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
num_word(Cash value)
|
|
|
|
{
|
|
|
|
static char buf[128];
|
|
|
|
static const char *small[] = {
|
|
|
|
"zero", "one", "two", "three", "four", "five", "six", "seven",
|
|
|
|
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
|
|
|
|
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty",
|
|
|
|
"thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
|
|
|
|
};
|
|
|
|
const char **big = small + 18;
|
|
|
|
int tu = value % 100;
|
|
|
|
|
|
|
|
/* deal with the simple cases first */
|
|
|
|
if (value <= 20)
|
|
|
|
return small[value];
|
|
|
|
|
|
|
|
/* is it an even multiple of 100? */
|
|
|
|
if (!tu)
|
|
|
|
{
|
|
|
|
sprintf(buf, "%s hundred", small[value / 100]);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* more than 99? */
|
|
|
|
if (value > 99)
|
|
|
|
{
|
|
|
|
/* is it an even multiple of 10 other than 10? */
|
|
|
|
if (value % 10 == 0 && tu > 10)
|
|
|
|
sprintf(buf, "%s hundred %s",
|
|
|
|
small[value / 100], big[tu / 10]);
|
|
|
|
else if (tu < 20)
|
|
|
|
sprintf(buf, "%s hundred and %s",
|
|
|
|
small[value / 100], small[tu]);
|
|
|
|
else
|
|
|
|
sprintf(buf, "%s hundred %s %s",
|
|
|
|
small[value / 100], big[tu / 10], small[tu % 10]);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* is it an even multiple of 10 other than 10? */
|
|
|
|
if (value % 10 == 0 && tu > 10)
|
|
|
|
sprintf(buf, "%s", big[tu / 10]);
|
|
|
|
else if (tu < 20)
|
|
|
|
sprintf(buf, "%s", small[tu]);
|
|
|
|
else
|
|
|
|
sprintf(buf, "%s %s", big[tu / 10], small[tu % 10]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
} /* num_word() */
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
static Datum
|
|
|
|
CashGetDatum(Cash value)
|
|
|
|
{
|
|
|
|
Cash *result = (Cash *) palloc(sizeof(Cash));
|
|
|
|
|
|
|
|
*result = value;
|
|
|
|
return PointerGetDatum(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-04-15 19:41:44 +02:00
|
|
|
/* cash_in()
|
|
|
|
* Convert a string to a cash data type.
|
|
|
|
* Format is [$]###[,]###[.##]
|
|
|
|
* Examples: 123.45 $123.45 $123,456.78
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1997-04-15 19:41:44 +02:00
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_in(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
Cash result;
|
1997-09-08 04:41:22 +02:00
|
|
|
Cash value = 0;
|
|
|
|
Cash dec = 0;
|
|
|
|
Cash sgn = 1;
|
|
|
|
int seen_dot = 0;
|
|
|
|
const char *s = str;
|
|
|
|
int fpoint;
|
|
|
|
char dsymbol,
|
|
|
|
ssymbol,
|
2007-01-03 02:19:51 +01:00
|
|
|
psymbol;
|
|
|
|
const char *nsymbol,
|
|
|
|
*csymbol;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-11-25 23:43:08 +01:00
|
|
|
struct lconv *lconvert = PGLC_localeconv();
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-11-18 04:55:51 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* frac_digits will be CHAR_MAX in some locales, notably C. However, just
|
|
|
|
* testing for == CHAR_MAX is risky, because of compilers like gcc that
|
|
|
|
* "helpfully" let you alter the platform-standard definition of whether
|
|
|
|
* char is signed or not. If we are so unfortunate as to get compiled
|
|
|
|
* with a nonstandard -fsigned-char or -funsigned-char switch, then our
|
|
|
|
* idea of CHAR_MAX will not agree with libc's. The safest course is not
|
|
|
|
* to test for CHAR_MAX at all, but to impose a range check for plausible
|
|
|
|
* frac_digits values.
|
2000-11-18 04:55:51 +01:00
|
|
|
*/
|
|
|
|
fpoint = lconvert->frac_digits;
|
|
|
|
if (fpoint < 0 || fpoint > 10)
|
|
|
|
fpoint = 2; /* best guess in this case, I think */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
|
|
|
ssymbol = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
|
|
|
csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
|
|
|
|
psymbol = ((*lconvert->positive_sign != '\0') ? *lconvert->positive_sign : '+');
|
|
|
|
nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-10-25 07:11:06 +02:00
|
|
|
#ifdef CASHDEBUG
|
1998-09-01 06:40:42 +02:00
|
|
|
printf("cashin- precision '%d'; decimal '%c'; thousands '%c'; currency '%s'; positive '%c'; negative '%s'\n",
|
|
|
|
fpoint, dsymbol, ssymbol, csymbol, psymbol, nsymbol);
|
1997-10-25 07:11:06 +02:00
|
|
|
#endif
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* we need to add all sorts of checking here. For now just */
|
1998-03-02 01:13:36 +01:00
|
|
|
/* strip all leading whitespace and any leading currency symbol */
|
2000-12-03 21:45:40 +01:00
|
|
|
while (isspace((unsigned char) *s))
|
1998-09-01 06:40:42 +02:00
|
|
|
s++;
|
|
|
|
if (strncmp(s, csymbol, strlen(csymbol)) == 0)
|
|
|
|
s += strlen(csymbol);
|
1998-03-02 01:13:36 +01:00
|
|
|
|
|
|
|
#ifdef CASHDEBUG
|
1998-09-01 06:40:42 +02:00
|
|
|
printf("cashin- string is '%s'\n", s);
|
1998-03-02 01:13:36 +01:00
|
|
|
#endif
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* a leading minus or paren signifies a negative number */
|
|
|
|
/* again, better heuristics needed */
|
2007-01-03 02:19:51 +01:00
|
|
|
/* XXX - doesn't properly check for balanced parens - djmc */
|
1998-09-01 06:40:42 +02:00
|
|
|
if (strncmp(s, nsymbol, strlen(nsymbol)) == 0)
|
1998-03-02 01:13:36 +01:00
|
|
|
{
|
|
|
|
sgn = -1;
|
|
|
|
s += strlen(nsymbol);
|
|
|
|
#ifdef CASHDEBUG
|
1998-09-01 06:40:42 +02:00
|
|
|
printf("cashin- negative symbol; string is '%s'\n", s);
|
1998-03-02 01:13:36 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (*s == '(')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
sgn = -1;
|
|
|
|
s++;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else if (*s == psymbol)
|
|
|
|
s++;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1998-03-02 01:13:36 +01:00
|
|
|
#ifdef CASHDEBUG
|
1998-09-01 06:40:42 +02:00
|
|
|
printf("cashin- string is '%s'\n", s);
|
1998-03-02 01:13:36 +01:00
|
|
|
#endif
|
|
|
|
|
2000-12-03 21:45:40 +01:00
|
|
|
while (isspace((unsigned char) *s))
|
1998-09-01 06:40:42 +02:00
|
|
|
s++;
|
|
|
|
if (strncmp(s, csymbol, strlen(csymbol)) == 0)
|
|
|
|
s += strlen(csymbol);
|
1998-03-02 01:13:36 +01:00
|
|
|
|
|
|
|
#ifdef CASHDEBUG
|
1998-09-01 06:40:42 +02:00
|
|
|
printf("cashin- string is '%s'\n", s);
|
1998-03-02 01:13:36 +01:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (;; s++)
|
|
|
|
{
|
2007-01-03 02:19:51 +01:00
|
|
|
/* we look for digits as int8 as we have less */
|
1997-09-07 07:04:48 +02:00
|
|
|
/* than the required number of decimal places */
|
2000-12-03 21:45:40 +01:00
|
|
|
if (isdigit((unsigned char) *s) && dec < fpoint)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
value = (value * 10) + *s - '0';
|
|
|
|
|
|
|
|
if (seen_dot)
|
|
|
|
dec++;
|
|
|
|
|
|
|
|
}
|
2007-01-03 02:19:51 +01:00
|
|
|
/* decimal point? then start counting fractions... */
|
1997-09-07 07:04:48 +02:00
|
|
|
else if (*s == dsymbol && !seen_dot)
|
|
|
|
{
|
|
|
|
seen_dot = 1;
|
|
|
|
|
|
|
|
}
|
2007-01-03 02:19:51 +01:00
|
|
|
/* "thousands" separator? then skip... */
|
1997-09-07 07:04:48 +02:00
|
|
|
else if (*s == ssymbol)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* round off */
|
2000-12-03 21:45:40 +01:00
|
|
|
if (isdigit((unsigned char) *s) && *s >= '5')
|
1997-09-07 07:04:48 +02:00
|
|
|
value++;
|
|
|
|
|
|
|
|
/* adjust for less than required decimal places */
|
|
|
|
for (; dec < fpoint; dec++)
|
|
|
|
value *= 10;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2007-07-13 01:51:10 +02:00
|
|
|
/* should only be trailing digits followed by whitespace or right paren */
|
|
|
|
while (isdigit((unsigned char) *s))
|
|
|
|
s++;
|
2007-01-03 02:19:51 +01:00
|
|
|
while (isspace((unsigned char) *s) || *s == ')')
|
1997-09-07 07:04:48 +02:00
|
|
|
s++;
|
1997-04-09 10:36:21 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (*s != '\0')
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("invalid input syntax for type money: \"%s\"", str)));
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2005-07-21 06:41:43 +02:00
|
|
|
result = value * sgn;
|
1997-04-09 10:36:21 +02:00
|
|
|
|
1998-03-02 01:13:36 +01:00
|
|
|
#ifdef CASHDEBUG
|
2000-08-03 18:35:08 +02:00
|
|
|
printf("cashin- result is %d\n", result);
|
1998-03-02 01:13:36 +01:00
|
|
|
#endif
|
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
|
|
|
|
1997-04-15 19:41:44 +02:00
|
|
|
/* cash_out()
|
|
|
|
* Function to convert cash to a dollars and cents representation.
|
|
|
|
* XXX HACK This code appears to assume US conventions for
|
1997-09-07 07:04:48 +02:00
|
|
|
* positive-valued amounts. - tgl 97/04/14
|
1997-04-15 19:41:44 +02:00
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_out(PG_FUNCTION_ARGS)
|
1997-04-09 10:36:21 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash value = PG_GETARG_CASH(0);
|
1997-09-08 04:41:22 +02:00
|
|
|
char *result;
|
|
|
|
char buf[CASH_BUFSZ];
|
|
|
|
int minus = 0;
|
|
|
|
int count = LAST_DIGIT;
|
|
|
|
int point_pos;
|
|
|
|
int comma_position = 0;
|
2000-11-18 04:55:51 +01:00
|
|
|
int points,
|
|
|
|
mon_group;
|
|
|
|
char comma;
|
2007-01-03 02:19:51 +01:00
|
|
|
const char *csymbol,
|
1997-09-08 04:41:22 +02:00
|
|
|
*nsymbol;
|
2007-01-03 02:19:51 +01:00
|
|
|
char dsymbol;
|
1997-09-08 04:41:22 +02:00
|
|
|
char convention;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-11-25 23:43:08 +01:00
|
|
|
struct lconv *lconvert = PGLC_localeconv();
|
1997-10-03 15:10:06 +02:00
|
|
|
|
2000-11-18 04:55:51 +01:00
|
|
|
/* see comments about frac_digits in cash_in() */
|
|
|
|
points = lconvert->frac_digits;
|
|
|
|
if (points < 0 || points > 10)
|
|
|
|
points = 2; /* best guess in this case, I think */
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* As with frac_digits, must apply a range check to mon_grouping to avoid
|
|
|
|
* being fooled by variant CHAR_MAX values.
|
2000-11-18 04:55:51 +01:00
|
|
|
*/
|
1997-10-03 15:10:06 +02:00
|
|
|
mon_group = *lconvert->mon_grouping;
|
2000-11-18 04:55:51 +01:00
|
|
|
if (mon_group <= 0 || mon_group > 6)
|
|
|
|
mon_group = 3;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
comma = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
1997-10-03 15:10:06 +02:00
|
|
|
convention = lconvert->n_sign_posn;
|
1998-09-01 06:40:42 +02:00
|
|
|
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
|
|
|
csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
|
|
|
|
nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
point_pos = LAST_DIGIT - points;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* allow more than three decimal points and separate them */
|
|
|
|
if (comma)
|
|
|
|
{
|
|
|
|
point_pos -= (points - 1) / mon_group;
|
|
|
|
comma_position = point_pos % (mon_group + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we work with positive amounts and add the minus sign at the end */
|
1997-09-13 14:05:32 +02:00
|
|
|
if (value < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
minus = 1;
|
2002-02-19 23:19:34 +01:00
|
|
|
value = -value;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* allow for trailing negative strings */
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet(buf, ' ', CASH_BUFSZ);
|
1997-09-07 07:04:48 +02:00
|
|
|
buf[TERMINATOR] = buf[LAST_PAREN] = '\0';
|
|
|
|
|
1997-09-13 14:05:32 +02:00
|
|
|
while (value || count > (point_pos - 2))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
if (points && count == point_pos)
|
|
|
|
buf[count--] = dsymbol;
|
|
|
|
else if (comma && count % (mon_group + 1) == comma_position)
|
|
|
|
buf[count--] = comma;
|
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
buf[count--] = ((uint64) value % 10) + '0';
|
|
|
|
value = ((uint64) value) / 10;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
strncpy((buf + count - strlen(csymbol) + 1), csymbol, strlen(csymbol));
|
|
|
|
count -= strlen(csymbol) - 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (buf[LAST_DIGIT] == ',')
|
|
|
|
buf[LAST_DIGIT] = buf[LAST_PAREN];
|
|
|
|
|
|
|
|
/* see if we need to signify negative amount */
|
|
|
|
if (minus)
|
|
|
|
{
|
2006-03-19 23:22:56 +01:00
|
|
|
result = palloc(CASH_BUFSZ + 2 - count + strlen(nsymbol));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* Position code of 0 means use parens */
|
|
|
|
if (convention == 0)
|
|
|
|
sprintf(result, "(%s)", buf + count);
|
|
|
|
else if (convention == 2)
|
|
|
|
sprintf(result, "%s%s", buf + count, nsymbol);
|
|
|
|
else
|
|
|
|
sprintf(result, "%s%s", nsymbol, buf + count);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
else
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2006-03-19 23:22:56 +01:00
|
|
|
result = palloc(CASH_BUFSZ + 2 - count);
|
1997-09-07 07:04:48 +02:00
|
|
|
strcpy(result, buf + count);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2003-05-13 20:03:08 +02:00
|
|
|
/*
|
|
|
|
* cash_recv - converts external binary format to cash
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
cash_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
2007-08-21 05:14:36 +02:00
|
|
|
PG_RETURN_CASH((Cash) pq_getmsgint64(buf));
|
2003-05-13 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cash_send - converts cash to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
cash_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Cash arg1 = PG_GETARG_CASH(0);
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
2007-08-21 05:14:36 +02:00
|
|
|
pq_sendint64(&buf, arg1);
|
2003-05-13 20:03:08 +02:00
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2003-08-17 21:58:06 +02:00
|
|
|
/*
|
|
|
|
* Comparison functions
|
|
|
|
*/
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_eq(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 == c2);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_ne(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 != c2);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_lt(PG_FUNCTION_ARGS)
|
1997-04-09 10:36:21 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 < c2);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_le(PG_FUNCTION_ARGS)
|
1997-04-09 10:36:21 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 <= c2);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_gt(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 > c2);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_ge(PG_FUNCTION_ARGS)
|
1997-04-09 10:36:21 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_BOOL(c1 >= c2);
|
|
|
|
}
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2003-08-17 21:58:06 +02:00
|
|
|
Datum
|
|
|
|
cash_cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
|
|
|
|
|
|
|
if (c1 > c2)
|
|
|
|
PG_RETURN_INT32(1);
|
|
|
|
else if (c1 == c2)
|
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
else
|
|
|
|
PG_RETURN_INT32(-1);
|
|
|
|
}
|
|
|
|
|
1997-04-09 10:36:21 +02:00
|
|
|
|
1997-04-15 19:41:44 +02:00
|
|
|
/* cash_pl()
|
|
|
|
* Add two cash values.
|
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_pl(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
result = c1 + c2;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* cash_mi()
|
|
|
|
* Subtract two cash values.
|
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cash_mi(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
result = c1 - c2;
|
1997-04-09 10:36:21 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
|
|
|
|
1997-09-20 18:15:34 +02:00
|
|
|
/* cash_mul_flt8()
|
|
|
|
* Multiply cash by float8.
|
1997-04-15 19:41:44 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
cash_mul_flt8(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
float8 f = PG_GETARG_FLOAT8(1);
|
|
|
|
Cash result;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = c * f;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
|
|
|
|
1997-09-20 18:15:34 +02:00
|
|
|
/* flt8_mul_cash()
|
|
|
|
* Multiply float8 by cash.
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
flt8_mul_cash(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 f = PG_GETARG_FLOAT8(0);
|
|
|
|
Cash c = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
result = f * c;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* cash_div_flt8()
|
|
|
|
* Divide cash by float8.
|
1997-04-15 19:41:44 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
cash_div_flt8(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
float8 f = PG_GETARG_FLOAT8(1);
|
|
|
|
Cash result;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
if (f == 0.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
1997-08-22 01:57:00 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = rint(c / f);
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
|
1997-09-20 18:15:34 +02:00
|
|
|
/* cash_mul_flt4()
|
|
|
|
* Multiply cash by float4.
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
cash_mul_flt4(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
float4 f = PG_GETARG_FLOAT4(1);
|
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = c * f;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* flt4_mul_cash()
|
2000-08-01 20:29:35 +02:00
|
|
|
* Multiply float4 by cash.
|
1997-09-20 18:15:34 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
flt4_mul_cash(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 f = PG_GETARG_FLOAT4(0);
|
|
|
|
Cash c = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
result = f * c;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* cash_div_flt4()
|
|
|
|
* Divide cash by float4.
|
|
|
|
*
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
cash_div_flt4(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
float4 f = PG_GETARG_FLOAT4(1);
|
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
if (f == 0.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = rint(c / f);
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
/* cash_mul_int8()
|
|
|
|
* Multiply cash by int8.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
cash_mul_int8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
int64 i = PG_GETARG_INT64(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
result = c * i;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* int8_mul_cash()
|
|
|
|
* Multiply int8 by cash.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
int8_mul_cash(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int64 i = PG_GETARG_INT64(0);
|
|
|
|
Cash c = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
result = i * c;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cash_div_int8()
|
|
|
|
* Divide cash by 8-byte integer.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
cash_div_int8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
int64 i = PG_GETARG_INT64(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
|
|
|
result = rint(c / i);
|
|
|
|
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-09-20 18:15:34 +02:00
|
|
|
/* cash_mul_int4()
|
|
|
|
* Multiply cash by int4.
|
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
cash_mul_int4(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-13 09:35:40 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
2007-08-21 05:56:07 +02:00
|
|
|
int32 i = PG_GETARG_INT32(1);
|
2000-06-13 09:35:40 +02:00
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-13 09:35:40 +02:00
|
|
|
result = c * i;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* int4_mul_cash()
|
|
|
|
* Multiply int4 by cash.
|
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
int4_mul_cash(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-13 09:35:40 +02:00
|
|
|
int32 i = PG_GETARG_INT32(0);
|
|
|
|
Cash c = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
|
|
|
|
|
|
|
result = i * c;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* cash_div_int4()
|
|
|
|
* Divide cash by 4-byte integer.
|
|
|
|
*
|
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
cash_div_int4(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-13 09:35:40 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
2007-08-21 05:56:07 +02:00
|
|
|
int32 i = PG_GETARG_INT32(1);
|
2000-06-13 09:35:40 +02:00
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
if (i == 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-13 09:35:40 +02:00
|
|
|
result = rint(c / i);
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-13 09:35:40 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* cash_mul_int2()
|
|
|
|
* Multiply cash by int2.
|
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
cash_mul_int2(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
int16 s = PG_GETARG_INT16(1);
|
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
result = c * s;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
/* int2_mul_cash()
|
|
|
|
* Multiply int2 by cash.
|
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
int2_mul_cash(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
int16 s = PG_GETARG_INT16(0);
|
|
|
|
Cash c = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
result = s * c;
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
/* cash_div_int2()
|
|
|
|
* Divide cash by int2.
|
|
|
|
*
|
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
cash_div_int2(PG_FUNCTION_ARGS)
|
1997-09-20 18:15:34 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
Cash c = PG_GETARG_CASH(0);
|
|
|
|
int16 s = PG_GETARG_INT16(1);
|
|
|
|
Cash result;
|
1997-09-20 18:15:34 +02:00
|
|
|
|
|
|
|
if (s == 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
1997-09-20 18:15:34 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
result = rint(c / s);
|
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
|
|
|
/* cashlarger()
|
|
|
|
* Return larger of two cash values.
|
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cashlarger(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
result = (c1 > c2) ? c1 : c2;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
|
|
|
/* cashsmaller()
|
|
|
|
* Return smaller of two cash values.
|
|
|
|
*/
|
2000-08-03 18:35:08 +02:00
|
|
|
Datum
|
|
|
|
cashsmaller(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-08-03 18:35:08 +02:00
|
|
|
Cash c1 = PG_GETARG_CASH(0);
|
|
|
|
Cash c2 = PG_GETARG_CASH(1);
|
|
|
|
Cash result;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
result = (c1 < c2) ? c1 : c2;
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-08-03 18:35:08 +02:00
|
|
|
PG_RETURN_CASH(result);
|
|
|
|
}
|
1997-04-15 19:41:44 +02:00
|
|
|
|
2000-07-07 20:49:56 +02:00
|
|
|
/* cash_words()
|
1997-08-22 09:13:01 +02:00
|
|
|
* This converts a int4 as well but to a representation using words
|
1997-04-15 19:41:44 +02:00
|
|
|
* Obviously way North American centric - sorry
|
|
|
|
*/
|
2000-07-06 07:48:31 +02:00
|
|
|
Datum
|
2000-07-07 20:49:56 +02:00
|
|
|
cash_words(PG_FUNCTION_ARGS)
|
1997-04-15 19:41:44 +02:00
|
|
|
{
|
2000-07-06 07:48:31 +02:00
|
|
|
Cash value = PG_GETARG_CASH(0);
|
2007-01-03 02:19:51 +01:00
|
|
|
uint64 val;
|
2002-08-20 18:46:29 +02:00
|
|
|
char buf[256];
|
1997-09-08 04:41:22 +02:00
|
|
|
char *p = buf;
|
|
|
|
Cash m0;
|
|
|
|
Cash m1;
|
|
|
|
Cash m2;
|
|
|
|
Cash m3;
|
2007-01-03 02:19:51 +01:00
|
|
|
Cash m4;
|
|
|
|
Cash m5;
|
|
|
|
Cash m6;
|
1999-05-25 18:15:34 +02:00
|
|
|
text *result;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* work with positive numbers */
|
2000-07-06 07:48:31 +02:00
|
|
|
if (value < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-06 07:48:31 +02:00
|
|
|
value = -value;
|
1997-09-07 07:04:48 +02:00
|
|
|
strcpy(buf, "minus ");
|
|
|
|
p += 6;
|
|
|
|
}
|
|
|
|
else
|
2000-07-06 07:48:31 +02:00
|
|
|
buf[0] = '\0';
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-02-19 23:19:34 +01:00
|
|
|
/* Now treat as unsigned, to avoid trouble at INT_MIN */
|
2007-01-03 02:19:51 +01:00
|
|
|
val = (uint64) value;
|
2002-02-19 23:19:34 +01:00
|
|
|
|
2007-01-03 02:19:51 +01:00
|
|
|
m0 = val % 100ll; /* cents */
|
|
|
|
m1 = (val / 100ll) % 1000; /* hundreds */
|
|
|
|
m2 = (val / 100000ll) % 1000; /* thousands */
|
|
|
|
m3 = val / 100000000ll % 1000; /* millions */
|
|
|
|
m4 = val / 100000000000ll % 1000; /* billions */
|
|
|
|
m5 = val / 100000000000000ll % 1000; /* trillions */
|
|
|
|
m6 = val / 100000000000000000ll % 1000; /* quadrillions */
|
|
|
|
|
|
|
|
if (m6)
|
|
|
|
{
|
|
|
|
strcat(buf, num_word(m6));
|
|
|
|
strcat(buf, " quadrillion ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m5)
|
|
|
|
{
|
|
|
|
strcat(buf, num_word(m5));
|
|
|
|
strcat(buf, " trillion ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m4)
|
|
|
|
{
|
|
|
|
strcat(buf, num_word(m4));
|
|
|
|
strcat(buf, " billion ");
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (m3)
|
|
|
|
{
|
|
|
|
strcat(buf, num_word(m3));
|
|
|
|
strcat(buf, " million ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m2)
|
|
|
|
{
|
|
|
|
strcat(buf, num_word(m2));
|
|
|
|
strcat(buf, " thousand ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m1)
|
|
|
|
strcat(buf, num_word(m1));
|
|
|
|
|
|
|
|
if (!*p)
|
|
|
|
strcat(buf, "zero");
|
|
|
|
|
2002-02-19 23:19:34 +01:00
|
|
|
strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
|
1997-09-07 07:04:48 +02:00
|
|
|
strcat(buf, num_word(m0));
|
|
|
|
strcat(buf, m0 == 1 ? " cent" : " cents");
|
1998-10-12 06:07:53 +02:00
|
|
|
|
|
|
|
/* capitalize output */
|
2004-05-07 02:24:59 +02:00
|
|
|
buf[0] = pg_toupper((unsigned char) buf[0]);
|
1998-10-12 06:07:53 +02:00
|
|
|
|
|
|
|
/* make a text type for output */
|
|
|
|
result = (text *) palloc(strlen(buf) + VARHDRSZ);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, strlen(buf) + VARHDRSZ);
|
2000-03-19 23:10:52 +01:00
|
|
|
memcpy(VARDATA(result), buf, strlen(buf));
|
1998-10-12 06:07:53 +02:00
|
|
|
|
2000-07-06 07:48:31 +02:00
|
|
|
PG_RETURN_TEXT_P(result);
|
|
|
|
}
|