]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/int.c
Update copyright for 2014
[postgresql] / src / backend / utils / adt / int.c
index 18755894ae4dfb4718560f139209774a0e0ba332..669355e4540a891ab8cfdc79326f1fe6bbe0f163 100644 (file)
@@ -3,12 +3,12 @@
  * int.c
  *       Functions for the built-in integer types (except int8).
  *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.87 2009/12/30 01:29:22 rhaas Exp $
+ *       src/backend/utils/adt/int.c
  *
  *-------------------------------------------------------------------------
  */
@@ -40,7 +40,7 @@
 
 #define SAMESIGN(a,b)  (((a) < 0) == ((b) < 0))
 
-#define Int2VectorSize(n)      (offsetof(int2vector, values) + (n) * sizeof(int2))
+#define Int2VectorSize(n)      (offsetof(int2vector, values) + (n) * sizeof(int16))
 
 typedef struct
 {
@@ -109,14 +109,14 @@ int2send(PG_FUNCTION_ARGS)
  * If int2s is NULL then caller must fill values[] afterward
  */
 int2vector *
-buildint2vector(const int2 *int2s, int n)
+buildint2vector(const int16 *int2s, int n)
 {
        int2vector *result;
 
        result = (int2vector *) palloc0(Int2VectorSize(n));
 
        if (n > 0 && int2s)
-               memcpy(result->values, int2s, n * sizeof(int2));
+               memcpy(result->values, int2s, n * sizeof(int16));
 
        /*
         * Attach standard array header.  For historical reasons, we set the index
@@ -149,7 +149,7 @@ int2vectorin(PG_FUNCTION_ARGS)
                while (*intString && isspace((unsigned char) *intString))
                        intString++;
                if (*intString == '\0')
-                       break;          
+                       break;
                result->values[n] = pg_atoi(intString, sizeof(int16), ' ');
                while (*intString && !isspace((unsigned char) *intString))
                        intString++;
@@ -213,7 +213,8 @@ int2vectorrecv(PG_FUNCTION_ARGS)
         * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
         * parameter.
         */
-       InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3, NULL, NULL);
+       InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
+                                                        InvalidOid, NULL, NULL);
 
        locfcinfo.arg[0] = PointerGetDatum(buf);
        locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);
@@ -265,7 +266,7 @@ int2vectoreq(PG_FUNCTION_ARGS)
 
        if (a->dim1 != b->dim1)
                PG_RETURN_BOOL(false);
-       PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int2)) == 0);
+       PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int16)) == 0);
 }
 
 
@@ -680,18 +681,6 @@ int4mul(PG_FUNCTION_ARGS)
        int32           arg2 = PG_GETARG_INT32(1);
        int32           result;
 
-#ifdef WIN32
-
-       /*
-        * Win32 doesn't throw a catchable exception for SELECT -2147483648 *
-        * (-1);  -- INT_MIN
-        */
-       if (arg2 == -1 && arg1 == INT_MIN)
-               ereport(ERROR,
-                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                                errmsg("integer out of range")));
-#endif
-
        result = arg1 * arg2;
 
        /*
@@ -708,7 +697,8 @@ int4mul(PG_FUNCTION_ARGS)
        if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX &&
                  arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
                arg2 != 0 &&
-               (result / arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0)))
+               ((arg2 == -1 && arg1 < 0 && result < 0) ||
+                result / arg2 != arg1))
                ereport(ERROR,
                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                 errmsg("integer out of range")));
@@ -723,34 +713,35 @@ int4div(PG_FUNCTION_ARGS)
        int32           result;
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
-
-#ifdef WIN32
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
 
        /*
-        * Win32 doesn't throw a catchable exception for SELECT -2147483648 /
-        * (-1); -- INT_MIN
+        * INT_MIN / -1 is problematic, since the result can't be represented on a
+        * two's-complement machine.  Some machines produce INT_MIN, some produce
+        * zero, some throw an exception.  We can dodge the problem by recognizing
+        * that division by -1 is the same as negation.
         */
-       if (arg2 == -1 && arg1 == INT_MIN)
-               ereport(ERROR,
-                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                                errmsg("integer out of range")));
-#endif
+       if (arg2 == -1)
+       {
+               result = -arg1;
+               /* overflow check (needed for INT_MIN) */
+               if (arg1 != 0 && SAMESIGN(result, arg1))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                        errmsg("integer out of range")));
+               PG_RETURN_INT32(result);
+       }
+
+       /* No overflow is possible */
 
        result = arg1 / arg2;
 
-       /*
-        * Overflow check.      The only possible overflow case is for arg1 = INT_MIN,
-        * arg2 = -1, where the correct result is -INT_MIN, which can't be
-        * represented on a two's-complement machine.  Most machines produce
-        * INT_MIN but it seems some produce zero.
-        */
-       if (arg2 == -1 && arg1 < 0 && result <= 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                                errmsg("integer out of range")));
        PG_RETURN_INT32(result);
 }
 
@@ -864,22 +855,35 @@ int2div(PG_FUNCTION_ARGS)
        int16           result;
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
-
-       result = arg1 / arg2;
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
 
        /*
-        * Overflow check.      The only possible overflow case is for arg1 =
-        * SHRT_MIN, arg2 = -1, where the correct result is -SHRT_MIN, which can't
-        * be represented on a two's-complement machine.  Most machines produce
-        * SHRT_MIN but it seems some produce zero.
+        * SHRT_MIN / -1 is problematic, since the result can't be represented on
+        * a two's-complement machine.  Some machines produce SHRT_MIN, some
+        * produce zero, some throw an exception.  We can dodge the problem by
+        * recognizing that division by -1 is the same as negation.
         */
-       if (arg2 == -1 && arg1 < 0 && result <= 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                                errmsg("smallint out of range")));
+       if (arg2 == -1)
+       {
+               result = -arg1;
+               /* overflow check (needed for SHRT_MIN) */
+               if (arg1 != 0 && SAMESIGN(result, arg1))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                        errmsg("smallint out of range")));
+               PG_RETURN_INT16(result);
+       }
+
+       /* No overflow is possible */
+
+       result = arg1 / arg2;
+
        PG_RETURN_INT16(result);
 }
 
@@ -1048,22 +1052,35 @@ int42div(PG_FUNCTION_ARGS)
        int32           result;
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
-
-       result = arg1 / arg2;
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
 
        /*
-        * Overflow check.      The only possible overflow case is for arg1 = INT_MIN,
-        * arg2 = -1, where the correct result is -INT_MIN, which can't be
-        * represented on a two's-complement machine.  Most machines produce
-        * INT_MIN but it seems some produce zero.
+        * INT_MIN / -1 is problematic, since the result can't be represented on a
+        * two's-complement machine.  Some machines produce INT_MIN, some produce
+        * zero, some throw an exception.  We can dodge the problem by recognizing
+        * that division by -1 is the same as negation.
         */
-       if (arg2 == -1 && arg1 < 0 && result <= 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                                errmsg("integer out of range")));
+       if (arg2 == -1)
+       {
+               result = -arg1;
+               /* overflow check (needed for INT_MIN) */
+               if (arg1 != 0 && SAMESIGN(result, arg1))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                        errmsg("integer out of range")));
+               PG_RETURN_INT32(result);
+       }
+
+       /* No overflow is possible */
+
+       result = arg1 / arg2;
+
        PG_RETURN_INT32(result);
 }
 
@@ -1074,12 +1091,20 @@ int4mod(PG_FUNCTION_ARGS)
        int32           arg2 = PG_GETARG_INT32(1);
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
 
-       /* SELECT ((-2147483648)::int4) % (-1); causes a floating point exception */
-       if (arg1 == INT_MIN && arg2 == -1)
+       /*
+        * Some machines throw a floating-point exception for INT_MIN % -1, which
+        * is a bit silly since the correct answer is perfectly well-defined,
+        * namely zero.
+        */
+       if (arg2 == -1)
                PG_RETURN_INT32(0);
 
        /* No overflow is possible */
@@ -1094,9 +1119,23 @@ int2mod(PG_FUNCTION_ARGS)
        int16           arg2 = PG_GETARG_INT16(1);
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
+
+       /*
+        * Some machines throw a floating-point exception for INT_MIN % -1, which
+        * is a bit silly since the correct answer is perfectly well-defined,
+        * namely zero.  (It's not clear this ever happens when dealing with
+        * int16, but we might as well have the test for safety.)
+        */
+       if (arg2 == -1)
+               PG_RETURN_INT16(0);
+
        /* No overflow is possible */
 
        PG_RETURN_INT16(arg1 % arg2);
@@ -1360,6 +1399,10 @@ generate_series_step_int4(PG_FUNCTION_ARGS)
                /* increment current in preparation for next iteration */
                fctx->current += fctx->step;
 
+               /* if next-value computation overflows, this is the final result */
+               if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current))
+                       fctx->step = 0;
+
                /* do when there is more left to send */
                SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
        }