#include <limits.h>
#include <ctype.h>
#include <math.h>
-#include <locale.h>
#include "libpq/pqformat.h"
#include "utils/builtins.h"
printf("cashin- string is '%s'\n", s);
#endif
+ /*
+ * We accumulate the absolute amount in "value" and then apply the sign at
+ * the end. (The sign can appear before or after the digits, so it would
+ * be more complicated to do otherwise.) Because of the larger range of
+ * negative signed integers, we build "value" in the negative and then
+ * flip the sign at the end, catching most-negative-number overflow if
+ * necessary.
+ */
+
for (; *s; s++)
{
/* we look for digits as long as we have found less */
/* than the required number of decimal places */
if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint))
{
- value = (value * 10) + (*s - '0');
+ Cash newvalue = (value * 10) - (*s - '0');
+
+ if (newvalue / 10 != value)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ str, "money")));
+
+ value = newvalue;
if (seen_dot)
dec++;
/* round off if there's another digit */
if (isdigit((unsigned char) *s) && *s >= '5')
- value++;
+ value--; /* remember we build the value in the negative */
+
+ if (value > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ str, "money")));
/* adjust for less than required decimal places */
for (; dec < fpoint; dec++)
- value *= 10;
+ {
+ Cash newvalue = value * 10;
+
+ if (newvalue / 10 != value)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ str, "money")));
+
+ value = newvalue;
+ }
/*
* should only be trailing digits followed by whitespace, right paren,
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type money: \"%s\"",
- str)));
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "money", str)));
}
- result = value * sgn;
+ /* If the value is supposed to be positive, flip the sign, but check for
+ * the most negative number. */
+ if (sgn > 0)
+ {
+ result = -value;
+ if (result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ str, "money")));
+ }
+ else
+ result = value;
#ifdef CASHDEBUG
printf("cashin- result is " INT64_FORMAT "\n", result);
case 0:
if (cs_precedes)
result = psprintf("(%s%s%s)",
- csymbol,
- (sep_by_space == 1) ? " " : "",
- bufptr);
+ csymbol,
+ (sep_by_space == 1) ? " " : "",
+ bufptr);
else
result = psprintf("(%s%s%s)",
- bufptr,
- (sep_by_space == 1) ? " " : "",
- csymbol);
+ bufptr,
+ (sep_by_space == 1) ? " " : "",
+ csymbol);
break;
case 1:
default:
if (cs_precedes)
result = psprintf("%s%s%s%s%s",
- signsymbol,
- (sep_by_space == 2) ? " " : "",
- csymbol,
- (sep_by_space == 1) ? " " : "",
- bufptr);
+ signsymbol,
+ (sep_by_space == 2) ? " " : "",
+ csymbol,
+ (sep_by_space == 1) ? " " : "",
+ bufptr);
else
result = psprintf("%s%s%s%s%s",
- signsymbol,
- (sep_by_space == 2) ? " " : "",
- bufptr,
- (sep_by_space == 1) ? " " : "",
- csymbol);
+ signsymbol,
+ (sep_by_space == 2) ? " " : "",
+ bufptr,
+ (sep_by_space == 1) ? " " : "",
+ csymbol);
break;
case 2:
if (cs_precedes)
result = psprintf("%s%s%s%s%s",
- csymbol,
- (sep_by_space == 1) ? " " : "",
- bufptr,
- (sep_by_space == 2) ? " " : "",
- signsymbol);
+ csymbol,
+ (sep_by_space == 1) ? " " : "",
+ bufptr,
+ (sep_by_space == 2) ? " " : "",
+ signsymbol);
else
result = psprintf("%s%s%s%s%s",
- bufptr,
- (sep_by_space == 1) ? " " : "",
- csymbol,
- (sep_by_space == 2) ? " " : "",
- signsymbol);
+ bufptr,
+ (sep_by_space == 1) ? " " : "",
+ csymbol,
+ (sep_by_space == 2) ? " " : "",
+ signsymbol);
break;
case 3:
if (cs_precedes)
result = psprintf("%s%s%s%s%s",
- signsymbol,
- (sep_by_space == 2) ? " " : "",
- csymbol,
- (sep_by_space == 1) ? " " : "",
- bufptr);
+ signsymbol,
+ (sep_by_space == 2) ? " " : "",
+ csymbol,
+ (sep_by_space == 1) ? " " : "",
+ bufptr);
else
result = psprintf("%s%s%s%s%s",
- bufptr,
- (sep_by_space == 1) ? " " : "",
- signsymbol,
- (sep_by_space == 2) ? " " : "",
- csymbol);
+ bufptr,
+ (sep_by_space == 1) ? " " : "",
+ signsymbol,
+ (sep_by_space == 2) ? " " : "",
+ csymbol);
break;
case 4:
if (cs_precedes)
result = psprintf("%s%s%s%s%s",
- csymbol,
- (sep_by_space == 2) ? " " : "",
- signsymbol,
- (sep_by_space == 1) ? " " : "",
- bufptr);
+ csymbol,
+ (sep_by_space == 2) ? " " : "",
+ signsymbol,
+ (sep_by_space == 1) ? " " : "",
+ bufptr);
else
result = psprintf("%s%s%s%s%s",
- bufptr,
- (sep_by_space == 1) ? " " : "",
- csymbol,
- (sep_by_space == 2) ? " " : "",
- signsymbol);
+ bufptr,
+ (sep_by_space == 1) ? " " : "",
+ csymbol,
+ (sep_by_space == 2) ? " " : "",
+ signsymbol);
break;
}
}
/* cash_words()
- * This converts a int4 as well but to a representation using words
+ * This converts an int4 as well but to a representation using words
* Obviously way North American centric - sorry
*/
Datum