Attached is a patch that limits the range tested by horology to
authorBruce Momjian <bruce@momjian.us>
Thu, 20 Mar 2003 06:03:00 +0000 (06:03 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 20 Mar 2003 06:03:00 +0000 (06:03 +0000)
what is capable using integer-datatime timestamps. It does attempt
to exercise the maximum allowable timestamp range.
Also is a small error check when converting a timestamp from external
to internal format that prevents out of range timestamps from being
entered.

Files patched:
        Index: src/backend/utils/adt/timestamp.c
                Added range check to prevent out of range timestamps
                from being used.

        Index: src/test/regress/sql/horology.sql
        Index: src/test/regress/expected/horology-no-DST-before-1970.out
        Index: src/test/regress/expected/horology-solaris-1947.out
                Limited range of timestamps being checked to
                Jan 1, 4713 BC  to Dec 31, 294276

In creating this patch, I have seen some definite problems with integer
timestamps and how they react when used near their limits. For example,
the following statement gives the correct result:

        SELECT timestamp without time zone 'Jan 1, 4713 BC'
               + interval '109203489 days' AS "Dec 31, 294276";

However, this statement which is the logical inverse of the above
gives incorrect results:

        SELECT timestamp without time zone '12/31/294276'
             - timestamp without time zone 'Jan 1, 4713 BC' AS "109203489 Days";

John Cochran

src/backend/utils/adt/timestamp.c
src/test/regress/expected/horology-no-DST-before-1970.out
src/test/regress/expected/horology-solaris-1947.out
src/test/regress/expected/horology.out
src/test/regress/sql/horology.sql

index 2764fee906a09d80fc77c6d5ee62121c6dbb2c3b..feaec85b69ec0c8749e3691c6eec69e419658c36 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.80 2003/03/11 21:01:33 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.81 2003/03/20 06:02:59 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -964,6 +964,9 @@ tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
    time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
 #ifdef HAVE_INT64_TIMESTAMP
    *result = ((date * INT64CONST(86400000000)) + time);
+   if ((*result < 0 && date >= 0) || (*result >= 0 && date < 0))
+       elog(ERROR, "TIMESTAMP out of range '%04d-%02d-%02d'",
+           tm->tm_year, tm->tm_mon, tm->tm_mday);
 #else
    *result = ((date * 86400) + time);
 #endif
index 5a191c9370c2b6e21d2c1d8dfcee0f6322a5c644..269c169c62345d64d7a10180836f4a4e809e4333 100644 (file)
@@ -328,28 +328,28 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
-       Nov 27, 2733194       
------------------------------
- Sun Nov 27 00:00:00 2733194
-(1 row)
-
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
-       Nov 30, 5471101       
------------------------------
- Sat Nov 30 00:00:00 5471101
-(1 row)
-
-SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
-       Dec 31, 5874897       
------------------------------
- Tue Dec 31 00:00:00 5874897
-(1 row)
-
-SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
-  2147483493 Days  
--------------------
- @ 2147483493 days
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '106000000 days' AS "Feb 23, 285506";
+       Feb 23, 285506       
+----------------------------
+ Fri Feb 23 00:00:00 285506
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '107000000 days' AS "Jan 20, 288244";
+       Jan 20, 288244       
+----------------------------
+ Sat Jan 20 00:00:00 288244
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '109203489 days' AS "Dec 31, 294276";
+       Dec 31, 294276       
+----------------------------
+ Sun Dec 31 00:00:00 294276
+  (1 row)
+  
+SELECT timestamp without time zone '12/31/294276' - timestamp without time zone '12/23/1999' AS "106751991 Days";
+  106751991 Days  
+------------------
+ @ 106751991 days
 (1 row)
 
 -- Shorthand values
index 784900531d74b5a85be78328453fa72dbc3ab4dd..73402c1ead4ef4271aa2025ef36f2e9d97c48a0e 100644 (file)
@@ -328,28 +328,28 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
-       Nov 27, 2733194       
------------------------------
- Sun Nov 27 00:00:00 2733194
-(1 row)
-
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
-       Nov 30, 5471101       
------------------------------
- Sat Nov 30 00:00:00 5471101
-(1 row)
-
-SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
-       Dec 31, 5874897       
------------------------------
- Tue Dec 31 00:00:00 5874897
-(1 row)
-
-SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
-  2147483493 Days  
--------------------
- @ 2147483493 days
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '106000000 days' AS "Feb 23, 285506";
+       Feb 23, 285506       
+----------------------------
+ Fri Feb 23 00:00:00 285506
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '107000000 days' AS "Jan 20, 288244";
+       Jan 20, 288244       
+----------------------------
+ Sat Jan 20 00:00:00 288244
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '109203489 days' AS "Dec 31, 294276";
+       Dec 31, 294276       
+----------------------------
+ Sun Dec 31 00:00:00 294276
+  (1 row)
+  
+SELECT timestamp without time zone '12/31/294276' - timestamp without time zone '12/23/1999' AS "106751991 Days";
+  106751991 Days  
+------------------
+ @ 106751991 days
 (1 row)
 
 -- Shorthand values
index d91df1bd8292aaf062260d5b06fee57b0cfc11a7..831806c992b3b2970f4263e33ce8e3b0ccf46c39 100644 (file)
@@ -328,28 +328,28 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
  Fri Dec 31 23:59:59 1999
 (1 row)
 
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
-       Nov 27, 2733194       
------------------------------
- Sun Nov 27 00:00:00 2733194
-(1 row)
-
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
-       Nov 30, 5471101       
------------------------------
- Sat Nov 30 00:00:00 5471101
-(1 row)
-
-SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
-       Dec 31, 5874897       
------------------------------
- Tue Dec 31 00:00:00 5874897
-(1 row)
-
-SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
-  2147483493 Days  
--------------------
- @ 2147483493 days
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '106000000 days' AS "Feb 23, 285506";
+       Feb 23, 285506       
+----------------------------
+ Fri Feb 23 00:00:00 285506
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '107000000 days' AS "Jan 20, 288244";
+       Jan 20, 288244       
+----------------------------
+ Sat Jan 20 00:00:00 288244
+  (1 row)
+  
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '109203489 days' AS "Dec 31, 294276";
+       Dec 31, 294276       
+----------------------------
+ Sun Dec 31 00:00:00 294276
+  (1 row)
+  
+SELECT timestamp without time zone '12/31/294276' - timestamp without time zone '12/23/1999' AS "106751991 Days";
+  106751991 Days  
+------------------
+ @ 106751991 days
 (1 row)
 
 -- Shorthand values
index 0ff15e9711fcbaeb6b7b7d9d2d112983dff17b7a..88ac83b5add389dd8caec91fa823c9697b8d4b30 100644 (file)
@@ -76,10 +76,10 @@ SELECT timestamp without time zone '1996-03-01' - interval '1 second' AS "Feb 29
 SELECT timestamp without time zone '1999-03-01' - interval '1 second' AS "Feb 28";
 SELECT timestamp without time zone '2000-03-01' - interval '1 second' AS "Feb 29";
 SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second' AS "Dec 31";
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
-SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
-SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
-SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '106000000 days' AS "Feb 23, 285506";
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '107000000 days' AS "Jan 20, 288244";
+SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '109203489 days' AS "Dec 31, 294276";
+SELECT timestamp without time zone '12/31/294276' - timestamp without time zone '12/23/1999' AS "106751991 Days";
 
 -- Shorthand values
 -- Not directly usable for regression testing since these are not constants.