]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/cash.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / cash.c
index 015875875be13b636d807be454707cb5438e7a1a..5afadb65d115606605607a08de48eb1930d72685 100644 (file)
@@ -21,7 +21,6 @@
 #include <limits.h>
 #include <ctype.h>
 #include <math.h>
-#include <locale.h>
 
 #include "libpq/pqformat.h"
 #include "utils/builtins.h"
@@ -189,13 +188,30 @@ cash_in(PG_FUNCTION_ARGS)
        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++;
@@ -214,11 +230,27 @@ cash_in(PG_FUNCTION_ARGS)
 
        /* 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,
@@ -243,11 +275,23 @@ cash_in(PG_FUNCTION_ARGS)
                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);
@@ -382,79 +426,79 @@ cash_out(PG_FUNCTION_ARGS)
                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;
        }
 
@@ -893,7 +937,7 @@ cashsmaller(PG_FUNCTION_ARGS)
 }
 
 /* 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