diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 6b72e80e569905de6a8d455989334695c55bc9b3..17357d8408850c10bf8e9861ed5bce92c2c7a337 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.201 2007/05/21 17:10:28 petere Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.202 2007/05/29 04:58:43 neilc Exp $ --> <chapter id="datatype"> <title id="datatype-title">Data Types</title> @@ -1880,7 +1880,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 9d1fdd5f40c571e321da4d6648bfeafe659c1b01..b5cc2461589c98b1a8aeb64db0666a059e6a09e1 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.179 2007/05/27 20:32:16 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.180 2007/05/29 04:58:43 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -924,6 +924,7 @@ DecodeDateTime(char **field, int *ftype, int nf, #else *fsec = frac; #endif + tmask = DTK_ALL_SECS_M; } break; @@ -1699,6 +1700,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, #else *fsec = frac; #endif + tmask = DTK_ALL_SECS_M; } break; @@ -2805,6 +2807,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: @@ -2813,6 +2816,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: @@ -2822,7 +2826,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 df6cf5e4f308f92cb78620a5e90d6e3baf133439..34b88ad5c7a9e111f60c1fd1a871acc3c05daaba 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.65 2007/02/19 17:41:39 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.66 2007/05/29 04:58:43 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -100,17 +100,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 @@ -175,8 +177,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 63 /* 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 f7c35deca1a6d557e537998d3db50abfdfd31c7c..72a031df5f1d9f1d08e1b186fa0749690e6ad544 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -326,3 +326,26 @@ SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour"; @ 29 days 23 hours (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 9b2e62514dbbc5bb40b43c5d43574727aafe46ee..d081bf1ffedf2d504f2c422e49abd9a2a6a48045 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -116,3 +116,14 @@ SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as -- test justify_interval() SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour"; + +-- 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