aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/datetime.c44
-rw-r--r--src/test/regress/expected/interval.out6
-rw-r--r--src/test/regress/sql/interval.sql1
3 files changed, 13 insertions, 38 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index a1cf2b4ed54..9640684cb10 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.192 2008/09/11 15:27:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.193 2008/09/16 22:31:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -448,7 +448,7 @@ TrimTrailingZeros(char *str)
* DTK_TIME - digits, colon delimiters, and possibly a decimal point
* DTK_STRING - text (no digits or punctuation)
* DTK_SPECIAL - leading "+" or "-" followed by text
- * DTK_TZ - leading "+" or "-" followed by digits (also eats ':' or '.')
+ * DTK_TZ - leading "+" or "-" followed by digits (also eats ':', '.', '-')
*
* Note that some field types can hold unexpected items:
* DTK_NUMBER can hold date fields (yy.ddd)
@@ -610,12 +610,13 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
while (isspace((unsigned char) *cp))
cp++;
/* numeric timezone? */
+ /* note that "DTK_TZ" could also be a signed float or yyyy-mm */
if (isdigit((unsigned char) *cp))
{
ftype[nf] = DTK_TZ;
APPEND_CHAR(bufp, bufend, *cp++);
while (isdigit((unsigned char) *cp) ||
- *cp == ':' || *cp == '.')
+ *cp == ':' || *cp == '.' || *cp == '-')
APPEND_CHAR(bufp, bufend, *cp++);
}
/* special? */
@@ -2774,19 +2775,17 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
/*
* Timezone is a token with a leading sign character and
- * otherwise the same as a non-signed time field
+ * at least one digit; there could be ':', '.', '-'
+ * embedded in it as well.
*/
Assert(*field[i] == '-' || *field[i] == '+');
/*
- * A single signed number ends up here, but will be rejected
- * by DecodeTime(). So, work this out to drop through to
- * DTK_NUMBER, which *can* tolerate this.
+ * Try for hh:mm or hh:mm:ss. If not, fall through to
+ * DTK_NUMBER case, which can handle signed float numbers
+ * and signed year-month values.
*/
- cp = field[i] + 1;
- while (*cp != '\0' && *cp != ':' && *cp != '.')
- cp++;
- if (*cp == ':' &&
+ if (strchr(field[i] + 1, ':') != NULL &&
DecodeTime(field[i] + 1, fmask, INTERVAL_FULL_RANGE,
&tmask, tm, fsec) == 0)
{
@@ -2808,32 +2807,13 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
tmask = DTK_M(TZ);
break;
}
- else if (type == IGNORE_DTF)
- {
- if (*cp == '.')
- {
- /*
- * Got a decimal point? Then assume some sort of
- * seconds specification
- */
- type = DTK_SECOND;
- }
- else if (*cp == '\0')
- {
- /*
- * Only a signed integer? Then must assume a
- * timezone-like usage
- */
- type = DTK_HOUR;
- }
- }
/* FALL THROUGH */
case DTK_DATE:
case DTK_NUMBER:
if (type == IGNORE_DTF)
{
- /* use typmod to decide what rightmost integer field is */
+ /* use typmod to decide what rightmost field is */
switch (range)
{
case INTERVAL_MASK(YEAR):
@@ -2883,6 +2863,8 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
if (*cp != '\0')
return DTERR_BAD_FORMAT;
type = DTK_MONTH;
+ if (val < 0)
+ val2 = -val2;
val = val * MONTHS_PER_YEAR + val2;
fval = 0;
}
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a9b5766439b..82705163888 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -21,12 +21,6 @@ SELECT INTERVAL '-08:00' AS "Eight hours";
-08:00:00
(1 row)
-SELECT INTERVAL '-05' AS "Five hours";
- Five hours
-------------
- -05:00:00
-(1 row)
-
SELECT INTERVAL '-1 +02:03' AS "22 hours ago...";
22 hours ago...
-------------------
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index 06e47058591..732ca026f9f 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -8,7 +8,6 @@ SET DATESTYLE = 'ISO';
SELECT INTERVAL '01:00' AS "One hour";
SELECT INTERVAL '+02:00' AS "Two hours";
SELECT INTERVAL '-08:00' AS "Eight hours";
-SELECT INTERVAL '-05' AS "Five hours";
SELECT INTERVAL '-1 +02:03' AS "22 hours ago...";
SELECT INTERVAL '-1 days +02:03' AS "22 hours ago...";
SELECT INTERVAL '1.5 weeks' AS "Ten days twelve hours";