pgsql-4231

Version:

8.3.1

Bug Link:

http://archives.postgresql.org/pgsql-bugs/2008-06/msg00054.php

Patch Link:

http://archives.postgresql.org/pgsql-committers/2008-06/msg00131.php

Symptom:

On 64-bit machnie, when you make an interval by giving it a text representation of a number of seconds, it has an overflow without warning. And if it's not given as a string, there will be a conversion error.

How it is diagnosed:

Reproduced! So the interval type should only be treated as 32-bit integer, and anything larger than 32 bit integer should have caused postgres to reject the input by reporting overflow, yet in this buggy version it didn’t, but instead returned overflowed wrong result.

/* Instead of rejecting the input, it accepted invalid input and returned wrong result. */

postgres=#select '1584-10-14 00:00'::timestamp + '13424373496 seconds'::interval;

      ?column?

---------------------

 1601-11-17 21:13:28  <--- overflowed! Wrong!

(1 row)

//On 32-bit machine, there will be error

//ERROR:  interval field value out of range: "13424373496 seconds"

postgres=#select 13424373496::bigint % (2 ^ 32)::bigint;

 ?column?

-----------

 539471608

(1 row)

postgres=#select '1584-10-14 00:00'::timestamp + '539471608 seconds'::interval;

      ?column?

---------------------

 1601-11-17 21:13:28

(1 row)

postgres=#select '1584-10-14 00:00'::timestamp + 13424373496::interval;//if represent as int
ERROR:  cannot cast type bigint to interval
LINE 1: ...elect '1584-10-14 00:00'::timestamp + 13424373496::interval;
                                                                                                                    ^

Root Cause:

Brief:

In decoding the time, it uses strtol when it really meant strtoi -- they only accept integer values but not long integers.

Detail:

int

DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec)

{

        ...

        int                        val;

        ...

        /* read through list backwards to pick up units before values */

        for (i = nf - 1; i >= 0; i--)

        {

                switch (ftype[i])

                {

                        ...

                        case DTK_NUMBER:

-                                val = strtol(field[i], &cp, 10);//filed[i]=”13424373496”

+                                val = strtoi(field[i], &cp, 10);

                                //On 64-bit machine strtol decodes correctly

//to return a long value of 13424373496,

//but it needs to be converted to int32, i.e val’s type, result in //539471608, which seems to be in normal range

                                //On 32-bit machine,it’s converted to 2147483647

                                //i.e, out of range!

                                if (errno == ERANGE)

                                        return DTERR_FIELD_OVERFLOW;

                }

                …

        }

        ...

}

 /*
+  * strtoi --- just like strtol, but returns int not long
+  */
+ static int
+ strtoi(const char *nptr, char **endptr, int base)
+ {
+         long        val;
+
+         val = strtol(nptr, endptr, base);
+ #ifdef HAVE_LONG_INT_64
+         if (val != (long) ((int32) val))
+                 errno = ERANGE;
+ #endif
+         return (int) val;
+ }

Is there any log message?:

No.

Can ErrLog insert a log message?

Yest, return value of strtol, which is similar to the logic in strtoi.