1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Fix a bug in input processing for the "interval" type. Previously,

"microsecond" and "millisecond" units were not considered valid input
by themselves, which caused inputs like "1 millisecond" to be rejected
erroneously.

Update the docs, add regression tests, and backport to 8.2 and 8.1
This commit is contained in:
Neil Conway
2007-05-29 04:59:44 +00:00
parent 9ccf784833
commit 21b8d51de6
5 changed files with 65 additions and 15 deletions

View File

@ -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>,

View File

@ -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
/*
* 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:

View File

@ -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) */

View File

@ -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"

View File

@ -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