]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/int.c
Update copyright for 2014
[postgresql] / src / backend / utils / adt / int.c
index 194b96c720828c57f3fc73ecd465b8016e1a2765..669355e4540a891ab8cfdc79326f1fe6bbe0f163 100644 (file)
@@ -3,12 +3,12 @@
  * int.c
  *       Functions for the built-in integer types (except int8).
  *
- * Portions Copyright (c) 1996-2006, 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.76 2007/01/02 20:00:49 momjian Exp $
+ *       src/backend/utils/adt/int.c
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,6 @@
  *              int2in, int2out, int2recv, int2send
  *              int4in, int4out, int4recv, int4send
  *              int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
- *             Conversion routines:
- *              itoi, int2_text, int4_text
  *             Boolean operators:
  *              inteq, intne, intlt, intle, intgt, intge
  *             Arithmetic operators:
@@ -42,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
 {
@@ -111,20 +109,20 @@ 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
         * lower bound to 0 not 1.
         */
-       result->size = Int2VectorSize(n);
+       SET_VARSIZE(result, Int2VectorSize(n));
        result->ndim = 1;
        result->dataoffset = 0;         /* never any nulls */
        result->elemtype = INT2OID;
@@ -148,10 +146,11 @@ int2vectorin(PG_FUNCTION_ARGS)
 
        for (n = 0; *intString && n < FUNC_MAX_ARGS; n++)
        {
-               if (sscanf(intString, "%hd", &result->values[n]) != 1)
-                       break;
                while (*intString && isspace((unsigned char) *intString))
                        intString++;
+               if (*intString == '\0')
+                       break;
+               result->values[n] = pg_atoi(intString, sizeof(int16), ' ');
                while (*intString && !isspace((unsigned char) *intString))
                        intString++;
        }
@@ -162,7 +161,7 @@ int2vectorin(PG_FUNCTION_ARGS)
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("int2vector has too many elements")));
 
-       result->size = Int2VectorSize(n);
+       SET_VARSIZE(result, Int2VectorSize(n));
        result->ndim = 1;
        result->dataoffset = 0;         /* never any nulls */
        result->elemtype = INT2OID;
@@ -214,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);
@@ -227,13 +227,21 @@ int2vectorrecv(PG_FUNCTION_ARGS)
 
        Assert(!locfcinfo.isnull);
 
-       /* sanity checks: int2vector must be 1-D, no nulls */
+       /* sanity checks: int2vector must be 1-D, 0-based, no nulls */
        if (ARR_NDIM(result) != 1 ||
                ARR_HASNULL(result) ||
-               ARR_ELEMTYPE(result) != INT2OID)
+               ARR_ELEMTYPE(result) != INT2OID ||
+               ARR_LBOUND(result)[0] != 0)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                                 errmsg("invalid int2vector data")));
+
+       /* check length for consistency with int2vectorin() */
+       if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("oidvector has too many elements")));
+
        PG_RETURN_POINTER(result);
 }
 
@@ -258,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);
 }
 
 
@@ -343,68 +351,6 @@ i4toi2(PG_FUNCTION_ARGS)
        PG_RETURN_INT16((int16) arg1);
 }
 
-Datum
-int2_text(PG_FUNCTION_ARGS)
-{
-       int16           arg1 = PG_GETARG_INT16(0);
-       text       *result = (text *) palloc(7 + VARHDRSZ); /* sign,5 digits, '\0' */
-
-       pg_itoa(arg1, VARDATA(result));
-       VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
-       PG_RETURN_TEXT_P(result);
-}
-
-Datum
-text_int2(PG_FUNCTION_ARGS)
-{
-       text       *string = PG_GETARG_TEXT_P(0);
-       Datum           result;
-       int                     len;
-       char       *str;
-
-       len = VARSIZE(string) - VARHDRSZ;
-
-       str = palloc(len + 1);
-       memcpy(str, VARDATA(string), len);
-       *(str + len) = '\0';
-
-       result = DirectFunctionCall1(int2in, CStringGetDatum(str));
-       pfree(str);
-
-       return result;
-}
-
-Datum
-int4_text(PG_FUNCTION_ARGS)
-{
-       int32           arg1 = PG_GETARG_INT32(0);
-       text       *result = (text *) palloc(12 + VARHDRSZ);            /* sign,10 digits,'\0' */
-
-       pg_ltoa(arg1, VARDATA(result));
-       VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
-       PG_RETURN_TEXT_P(result);
-}
-
-Datum
-text_int4(PG_FUNCTION_ARGS)
-{
-       text       *string = PG_GETARG_TEXT_P(0);
-       Datum           result;
-       int                     len;
-       char       *str;
-
-       len = VARSIZE(string) - VARHDRSZ;
-
-       str = palloc(len + 1);
-       memcpy(str, VARDATA(string), len);
-       *(str + len) = '\0';
-
-       result = DirectFunctionCall1(int4in, CStringGetDatum(str));
-       pfree(str);
-
-       return result;
-}
-
 /* Cast int4 -> bool */
 Datum
 int4_bool(PG_FUNCTION_ARGS)
@@ -735,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;
 
        /*
@@ -763,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")));
@@ -778,33 +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.
-        */
-       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);
 }
 
@@ -918,21 +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.
+        * 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);
 }
 
@@ -1012,9 +963,14 @@ int24div(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();
+       }
+
        /* No overflow is possible */
        PG_RETURN_INT32((int32) arg1 / arg2);
 }
@@ -1096,21 +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.
+        * 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);
 }
 
@@ -1121,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 */
@@ -1141,42 +1119,26 @@ int2mod(PG_FUNCTION_ARGS)
        int16           arg2 = PG_GETARG_INT16(1);
 
        if (arg2 == 0)
+       {
                ereport(ERROR,
                                (errcode(ERRCODE_DIVISION_BY_ZERO),
                                 errmsg("division by zero")));
-       /* No overflow is possible */
-
-       PG_RETURN_INT16(arg1 % arg2);
-}
-
-Datum
-int24mod(PG_FUNCTION_ARGS)
-{
-       int16           arg1 = PG_GETARG_INT16(0);
-       int32           arg2 = PG_GETARG_INT32(1);
-
-       if (arg2 == 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_DIVISION_BY_ZERO),
-                                errmsg("division by zero")));
-       /* No overflow is possible */
-
-       PG_RETURN_INT32(arg1 % arg2);
-}
+               /* ensure compiler realizes we mustn't reach the division (gcc bug) */
+               PG_RETURN_NULL();
+       }
 
-Datum
-int42mod(PG_FUNCTION_ARGS)
-{
-       int32           arg1 = PG_GETARG_INT32(0);
-       int16           arg2 = PG_GETARG_INT16(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.  (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);
 
-       if (arg2 == 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_DIVISION_BY_ZERO),
-                                errmsg("division by zero")));
        /* No overflow is possible */
 
-       PG_RETURN_INT32(arg1 % arg2);
+       PG_RETURN_INT16(arg1 % arg2);
 }
 
 
@@ -1397,7 +1359,7 @@ generate_series_step_int4(PG_FUNCTION_ARGS)
                if (step == 0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                        errmsg("step size may not equal zero")));
+                                        errmsg("step size cannot equal zero")));
 
                /* create a function context for cross-call persistence */
                funcctx = SRF_FIRSTCALL_INIT();
@@ -1437,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));
        }