aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/datatype.sgml5
-rw-r--r--src/backend/utils/adt/datetime.c16
-rw-r--r--src/include/utils/datetime.h26
-rw-r--r--src/test/regress/expected/interval.out23
-rw-r--r--src/test/regress/sql/interval.sql10
5 files changed, 65 insertions, 15 deletions
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 8e353aaf702..072c96d44f4 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -1,5 +1,5 @@
<!--
-$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.163.2.3 2006/08/21 16:24:02 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.163.2.4 2007/05/29 04:59:44 neilc Exp $
-->
<chapter id="datatype">
@@ -1823,7 +1823,8 @@ January 8 04:05:06 1999 PST
</programlisting>
Where: <replaceable>quantity</> is a number (possibly signed);
- <replaceable>unit</> is <literal>second</literal>,
+ <replaceable>unit</> is <literal>microsecond</literal>,
+ <literal>millisecond</literal>, <literal>second</literal>,
<literal>minute</literal>, <literal>hour</literal>, <literal>day</literal>,
<literal>week</literal>, <literal>month</literal>, <literal>year</literal>,
<literal>decade</literal>, <literal>century</literal>, <literal>millennium</literal>,
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 63bc43debf9..bfb9564397f 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.160.2.2 2005/12/01 17:56:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.160.2.3 2007/05/29 04:59:44 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1240,6 +1240,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
#else
*fsec = frac;
#endif
+ tmask = DTK_ALL_SECS_M;
}
break;
@@ -2000,6 +2001,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
#else
*fsec = frac;
#endif
+ tmask = DTK_ALL_SECS_M;
}
break;
@@ -3117,6 +3119,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
#else
*fsec += (val + fval) * 1e-6;
#endif
+ tmask = DTK_M(MICROSECOND);
break;
case DTK_MILLISEC:
@@ -3125,6 +3128,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
#else
*fsec += (val + fval) * 1e-3;
#endif
+ tmask = DTK_M(MILLISECOND);
break;
case DTK_SECOND:
@@ -3134,7 +3138,15 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
#else
*fsec += fval;
#endif
- tmask = DTK_M(SECOND);
+ /*
+ * If any subseconds were specified, consider
+ * this microsecond and millisecond input as
+ * well.
+ */
+ if (fval == 0)
+ tmask = DTK_M(SECOND);
+ else
+ tmask = DTK_ALL_SECS_M;
break;
case DTK_MINUTE:
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 48b158e050b..e8e26533766 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.57 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.57.2.1 2007/05/29 04:59:44 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -99,17 +99,19 @@
#define HOUR 10
#define MINUTE 11
#define SECOND 12
-#define DOY 13
-#define DOW 14
-#define UNITS 15
-#define ADBC 16
+#define MILLISECOND 13
+#define MICROSECOND 14
+#define DOY 15
+#define DOW 16
+#define UNITS 17
+#define ADBC 18
/* these are only for relative dates */
-#define AGO 17
-#define ABS_BEFORE 18
-#define ABS_AFTER 19
+#define AGO 19
+#define ABS_BEFORE 20
+#define ABS_AFTER 21
/* generic fields to help with parsing */
-#define ISODATE 20
-#define ISOTIME 21
+#define ISODATE 22
+#define ISOTIME 23
/* reserved for unrecognized string values */
#define UNKNOWN_FIELD 31
@@ -172,8 +174,10 @@
#define DTK_M(t) (0x01 << (t))
+/* Convenvience: a second, plus any fractional component */
+#define DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND))
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
-#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
+#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M)
#define MAXDATELEN 51 /* maximum possible length of an input date
* string (not counting tr. null) */
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index d07dd3013dc..17b18a1a0f9 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -241,3 +241,26 @@ SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as
@ 7 mons 6 days 5 hours 4 mins 3 secs
(1 row)
+-- test fractional second input, and detection of duplicate units
+SET DATESTYLE = 'ISO';
+SELECT '1 millisecond'::interval, '1 microsecond'::interval,
+ '500 seconds 99 milliseconds 51 microseconds'::interval;
+ interval | interval | interval
+--------------+-----------------+-----------------
+ 00:00:00.001 | 00:00:00.000001 | 00:08:20.099051
+(1 row)
+
+SELECT '3 days 5 milliseconds'::interval;
+ interval
+---------------------
+ 3 days 00:00:00.005
+(1 row)
+
+SELECT '1 second 2 seconds'::interval; -- error
+ERROR: invalid input syntax for type interval: "1 second 2 seconds"
+SELECT '10 milliseconds 20 milliseconds'::interval; -- error
+ERROR: invalid input syntax for type interval: "10 milliseconds 20 milliseconds"
+SELECT '5.5 seconds 3 milliseconds'::interval; -- error
+ERROR: invalid input syntax for type interval: "5.5 seconds 3 milliseconds"
+SELECT '1:20:05 5 microseconds'::interval; -- error
+ERROR: invalid input syntax for type interval: "1:20:05 5 microseconds"
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index 25e58659e7d..920ce8a09a4 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -76,3 +76,13 @@ select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31
SELECT justify_hours(interval '6 months 3 days 52 hours 3 minutes 2 seconds') as "6 mons 5 days 4 hours 3 mins 2 seconds";
SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as "7 mons 6 days 5 hours 4 mins 3 seconds";
+-- test fractional second input, and detection of duplicate units
+SET DATESTYLE = 'ISO';
+SELECT '1 millisecond'::interval, '1 microsecond'::interval,
+ '500 seconds 99 milliseconds 51 microseconds'::interval;
+SELECT '3 days 5 milliseconds'::interval;
+
+SELECT '1 second 2 seconds'::interval; -- error
+SELECT '10 milliseconds 20 milliseconds'::interval; -- error
+SELECT '5.5 seconds 3 milliseconds'::interval; -- error
+SELECT '1:20:05 5 microseconds'::interval; -- error \ No newline at end of file