Commit d1031cde authored by Tom Lane's avatar Tom Lane

Adjust date/time input parsing code to correctly distinguish the four

SQLSTATE error codes required by SQL99 (invalid format, datetime field
overflow, interval field overflow, invalid time zone displacement value).
Also emit a HINT about DateStyle in cases where it seems appropriate.
Per recent gripes.
parent 37222260
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.90 2003/08/08 00:10:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.91 2003/08/27 23:29:27 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -62,20 +62,19 @@ date_in(PG_FUNCTION_ARGS) ...@@ -62,20 +62,19 @@ date_in(PG_FUNCTION_ARGS)
int tzp; int tzp;
int dtype; int dtype;
int nf; int nf;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for date: \"%s\"", str))); dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0)) if (dterr != 0)
ereport(ERROR, DateTimeParseError(dterr, str, "date");
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for date: \"%s\"", str)));
switch (dtype) switch (dtype)
{ {
...@@ -95,9 +94,8 @@ date_in(PG_FUNCTION_ARGS) ...@@ -95,9 +94,8 @@ date_in(PG_FUNCTION_ARGS)
break; break;
default: default:
ereport(ERROR, DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), break;
errmsg("invalid input syntax for date: \"%s\"", str)));
} }
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE; date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
...@@ -559,21 +557,20 @@ time_in(PG_FUNCTION_ARGS) ...@@ -559,21 +557,20 @@ time_in(PG_FUNCTION_ARGS)
*tm = &tt; *tm = &tt;
int tz; int tz;
int nf; int nf;
int dterr;
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int dtype; int dtype;
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for time: \"%s\"", str))); dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|| (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) if (dterr != 0)
ereport(ERROR, DateTimeParseError(dterr, str, "time");
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for time: \"%s\"", str)));
tm2time(tm, fsec, &result); tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod); AdjustTimeForTypmod(&result, typmod);
...@@ -1424,23 +1421,20 @@ timetz_in(PG_FUNCTION_ARGS) ...@@ -1424,23 +1421,20 @@ timetz_in(PG_FUNCTION_ARGS)
*tm = &tt; *tm = &tt;
int tz; int tz;
int nf; int nf;
int dterr;
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int dtype; int dtype;
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for time with time zone: \"%s\"", dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
str))); if (dterr == 0)
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) if (dterr != 0)
|| (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) DateTimeParseError(dterr, str, "time with time zone");
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for time with time zone: \"%s\"",
str)));
result = (TimeTzADT *) palloc(sizeof(TimeTzADT)); result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result); tm2timetz(tm, fsec, tz, result);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.115 2003/08/25 23:30:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.116 2003/08/27 23:29:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -699,7 +699,7 @@ TrimTrailingZeros(char *str) ...@@ -699,7 +699,7 @@ TrimTrailingZeros(char *str)
/* ParseDateTime() /* ParseDateTime()
* Break string into tokens based on a date/time context. * Break string into tokens based on a date/time context.
* Returns 0 if successful, -1 if bogus input detected. * Returns 0 if successful, DTERR code if bogus input detected.
* *
* timestr - the input string * timestr - the input string
* lowstr - workspace for field string storage (must be large enough for * lowstr - workspace for field string storage (must be large enough for
...@@ -745,7 +745,7 @@ ParseDateTime(const char *timestr, char *lowstr, ...@@ -745,7 +745,7 @@ ParseDateTime(const char *timestr, char *lowstr,
/* Record start of current field */ /* Record start of current field */
if (nf >= maxfields) if (nf >= maxfields)
return -1; return DTERR_BAD_FORMAT;
field[nf] = lp; field[nf] = lp;
/* leading digit? then date or time */ /* leading digit? then date or time */
...@@ -866,7 +866,7 @@ ParseDateTime(const char *timestr, char *lowstr, ...@@ -866,7 +866,7 @@ ParseDateTime(const char *timestr, char *lowstr,
} }
/* otherwise something wrong... */ /* otherwise something wrong... */
else else
return -1; return DTERR_BAD_FORMAT;
} }
/* ignore other punctuation but use as delimiter */ /* ignore other punctuation but use as delimiter */
else if (ispunct((unsigned char) *cp)) else if (ispunct((unsigned char) *cp))
...@@ -876,7 +876,7 @@ ParseDateTime(const char *timestr, char *lowstr, ...@@ -876,7 +876,7 @@ ParseDateTime(const char *timestr, char *lowstr,
} }
/* otherwise, something is not right... */ /* otherwise, something is not right... */
else else
return -1; return DTERR_BAD_FORMAT;
/* force in a delimiter after each field */ /* force in a delimiter after each field */
*lp++ = '\0'; *lp++ = '\0';
...@@ -891,7 +891,9 @@ ParseDateTime(const char *timestr, char *lowstr, ...@@ -891,7 +891,9 @@ ParseDateTime(const char *timestr, char *lowstr,
/* DecodeDateTime() /* DecodeDateTime()
* Interpret previously parsed fields for general date and time. * Interpret previously parsed fields for general date and time.
* Return 0 if full date, 1 if only time, and -1 if problems. * Return 0 if full date, 1 if only time, and negative DTERR code if problems.
* (Currently, all callers treat 1 as an error return too.)
*
* External format(s): * External format(s):
* "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>" * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
* "Fri Feb-7-1997 15:23:27" * "Fri Feb-7-1997 15:23:27"
...@@ -920,15 +922,16 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -920,15 +922,16 @@ DecodeDateTime(char **field, int *ftype, int nf,
* format */ * format */
int i; int i;
int val; int val;
int dterr;
int mer = HR24; int mer = HR24;
int haveTextMonth = FALSE; int haveTextMonth = FALSE;
int is2digits = FALSE; int is2digits = FALSE;
int bc = FALSE; int bc = FALSE;
/*** /*
* We'll insist on at least all of the date fields, but initialize the * We'll insist on at least all of the date fields, but initialize the
* remaining fields in case they are not set later... * remaining fields in case they are not set later...
***/ */
*dtype = DTK_DATE; *dtype = DTK_DATE;
tm->tm_hour = 0; tm->tm_hour = 0;
tm->tm_min = 0; tm->tm_min = 0;
...@@ -955,14 +958,15 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -955,14 +958,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
int val; int val;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
val = strtol(field[i], &cp, 10); val = strtol(field[i], &cp, 10);
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
/* Get the time zone from the end of the string */ /* Get the time zone from the end of the string */
if (DecodeTimezone(cp, tzp) != 0) dterr = DecodeTimezone(cp, tzp);
return -1; if (dterr)
return dterr;
tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ); tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
ptype = 0; ptype = 0;
...@@ -979,7 +983,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -979,7 +983,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
{ {
/* No time zone accepted? Then quit... */ /* No time zone accepted? Then quit... */
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
if (isdigit((unsigned char) *field[i]) || ptype != 0) if (isdigit((unsigned char) *field[i]) || ptype != 0)
{ {
...@@ -989,7 +993,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -989,7 +993,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
{ {
/* Sanity check; should not fail this test */ /* Sanity check; should not fail this test */
if (ptype != DTK_TIME) if (ptype != DTK_TIME)
return -1; return DTERR_BAD_FORMAT;
ptype = 0; ptype = 0;
} }
...@@ -999,23 +1003,28 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -999,23 +1003,28 @@ DecodeDateTime(char **field, int *ftype, int nf,
* time already... * time already...
*/ */
if ((fmask & DTK_TIME_M) == DTK_TIME_M) if ((fmask & DTK_TIME_M) == DTK_TIME_M)
return -1; return DTERR_BAD_FORMAT;
if ((cp = strchr(field[i], '-')) == NULL) if ((cp = strchr(field[i], '-')) == NULL)
return -1; return DTERR_BAD_FORMAT;
/* Get the time zone from the end of the string */ /* Get the time zone from the end of the string */
if (DecodeTimezone(cp, tzp) != 0) dterr = DecodeTimezone(cp, tzp);
return -1; if (dterr)
return dterr;
*cp = '\0'; *cp = '\0';
/* /*
* Then read the rest of the field as a * Then read the rest of the field as a
* concatenated time * concatenated time
*/ */
if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask, dterr = DecodeNumberField(strlen(field[i]), field[i],
&tmask, tm, fsec, &is2digits)) < 0) fmask,
return -1; &tmask, tm,
fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
/* /*
* modify tmask after returning from * modify tmask after returning from
...@@ -1025,27 +1034,33 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1025,27 +1034,33 @@ DecodeDateTime(char **field, int *ftype, int nf,
} }
else else
{ {
if (DecodePosixTimezone(field[i], tzp) != 0) dterr = DecodePosixTimezone(field[i], tzp);
return -1; if (dterr)
return dterr;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
tmask = DTK_M(TZ); tmask = DTK_M(TZ);
} }
} }
else if (DecodeDate(field[i], fmask, &tmask, tm) != 0) else
return -1; {
dterr = DecodeDate(field[i], fmask, &tmask, tm);
if (dterr)
return dterr;
}
break; break;
case DTK_TIME: case DTK_TIME:
if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
return -1; if (dterr)
return dterr;
/* /*
* Check upper limit on hours; other limits checked in * Check upper limit on hours; other limits checked in
* DecodeTime() * DecodeTime()
*/ */
if (tm->tm_hour > 23) if (tm->tm_hour > 23)
return -1; return DTERR_FIELD_OVERFLOW;
break; break;
case DTK_TZ: case DTK_TZ:
...@@ -1053,10 +1068,11 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1053,10 +1068,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
int tz; int tz;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
if (DecodeTimezone(field[i], &tz) != 0) dterr = DecodeTimezone(field[i], &tz);
return -1; if (dterr)
return dterr;
/* /*
* Already have a time zone? Then maybe this is the * Already have a time zone? Then maybe this is the
...@@ -1103,11 +1119,11 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1103,11 +1119,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
case DTK_SECOND: case DTK_SECOND:
break; break;
default: default:
return 1; return DTERR_BAD_FORMAT;
break; break;
} }
else if (*cp != '\0') else if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
switch (ptype) switch (ptype)
{ {
...@@ -1159,7 +1175,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1159,7 +1175,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
frac = strtod(cp, &cp); frac = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000); *fsec = rint(frac * 1000000);
#else #else
...@@ -1170,8 +1186,9 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1170,8 +1186,9 @@ DecodeDateTime(char **field, int *ftype, int nf,
case DTK_TZ: case DTK_TZ:
tmask = DTK_M(TZ); tmask = DTK_M(TZ);
if (DecodeTimezone(field[i], tzp) != 0) dterr = DecodeTimezone(field[i], tzp);
return -1; if (dterr)
return dterr;
break; break;
case DTK_JULIAN: case DTK_JULIAN:
...@@ -1187,7 +1204,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1187,7 +1204,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
time = strtod(cp, &cp); time = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
tmask |= DTK_TIME_M; tmask |= DTK_TIME_M;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
...@@ -1202,16 +1219,20 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1202,16 +1219,20 @@ DecodeDateTime(char **field, int *ftype, int nf,
case DTK_TIME: case DTK_TIME:
/* previous field was "t" for ISO time */ /* previous field was "t" for ISO time */
if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M), dterr = DecodeNumberField(strlen(field[i]), field[i],
&tmask, tm, fsec, &is2digits)) < 0) (fmask | DTK_DATE_M),
return -1; &tmask, tm,
fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
if (tmask != DTK_TIME_M) if (tmask != DTK_TIME_M)
return -1; return DTERR_BAD_FORMAT;
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
break; break;
} }
...@@ -1229,8 +1250,9 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1229,8 +1250,9 @@ DecodeDateTime(char **field, int *ftype, int nf,
/* Embedded decimal and no date yet? */ /* Embedded decimal and no date yet? */
if ((cp != NULL) && !(fmask & DTK_DATE_M)) if ((cp != NULL) && !(fmask & DTK_DATE_M))
{ {
if (DecodeDate(field[i], fmask, &tmask, tm) != 0) dterr = DecodeDate(field[i], fmask, &tmask, tm);
return -1; if (dterr)
return dterr;
} }
/* embedded decimal and several digits before? */ /* embedded decimal and several digits before? */
else if ((cp != NULL) && ((flen - strlen(cp)) > 2)) else if ((cp != NULL) && ((flen - strlen(cp)) > 2))
...@@ -1240,20 +1262,31 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1240,20 +1262,31 @@ DecodeDateTime(char **field, int *ftype, int nf,
* the type field to allow decoding other fields * the type field to allow decoding other fields
* later. Example: 20011223 or 040506 * later. Example: 20011223 or 040506
*/ */
if ((ftype[i] = DecodeNumberField(flen, field[i], fmask, dterr = DecodeNumberField(flen, field[i], fmask,
&tmask, tm, fsec, &is2digits)) < 0) &tmask, tm,
return -1; fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
} }
else if (flen > 4) else if (flen > 4)
{ {
if ((ftype[i] = DecodeNumberField(flen, field[i], fmask, dterr = DecodeNumberField(flen, field[i], fmask,
&tmask, tm, fsec, &is2digits)) < 0) &tmask, tm,
return -1; fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
} }
/* otherwise it is a single date/time field... */ /* otherwise it is a single date/time field... */
else if (DecodeNumber(flen, field[i], fmask, else
&tmask, tm, fsec, &is2digits) != 0) {
return -1; dterr = DecodeNumber(flen, field[i], fmask,
&tmask, tm,
fsec, &is2digits);
if (dterr)
return dterr;
}
} }
break; break;
...@@ -1274,7 +1307,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1274,7 +1307,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("\"current\" is no longer supported"))); errmsg("\"current\" is no longer supported")));
return -1; return DTERR_BAD_FORMAT;
break; break;
case DTK_NOW: case DTK_NOW:
...@@ -1356,7 +1389,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1356,7 +1389,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
tmask |= DTK_M(DTZ); tmask |= DTK_M(DTZ);
tm->tm_isdst = 1; tm->tm_isdst = 1;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp += val * 60; *tzp += val * 60;
break; break;
...@@ -1369,7 +1402,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1369,7 +1402,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
tmask |= DTK_M(TZ); tmask |= DTK_M(TZ);
tm->tm_isdst = 1; tm->tm_isdst = 1;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp = val * 60; *tzp = val * 60;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
break; break;
...@@ -1377,7 +1410,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1377,7 +1410,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
case TZ: case TZ:
tm->tm_isdst = 0; tm->tm_isdst = 0;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp = val * 60; *tzp = val * 60;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
break; break;
...@@ -1411,9 +1444,9 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1411,9 +1444,9 @@ DecodeDateTime(char **field, int *ftype, int nf,
*/ */
tmask = 0; tmask = 0;
/* No preceeding date? Then quit... */ /* No preceding date? Then quit... */
if ((fmask & DTK_DATE_M) != DTK_DATE_M) if ((fmask & DTK_DATE_M) != DTK_DATE_M)
return -1; return DTERR_BAD_FORMAT;
/*** /***
* We will need one of the following fields: * We will need one of the following fields:
...@@ -1425,22 +1458,22 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1425,22 +1458,22 @@ DecodeDateTime(char **field, int *ftype, int nf,
|| ((ftype[i + 1] != DTK_NUMBER) || ((ftype[i + 1] != DTK_NUMBER)
&& (ftype[i + 1] != DTK_TIME) && (ftype[i + 1] != DTK_TIME)
&& (ftype[i + 1] != DTK_DATE))) && (ftype[i + 1] != DTK_DATE)))
return -1; return DTERR_BAD_FORMAT;
ptype = val; ptype = val;
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
if (tmask & fmask) if (tmask & fmask)
return -1; return DTERR_BAD_FORMAT;
fmask |= tmask; fmask |= tmask;
} }
...@@ -1477,18 +1510,18 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1477,18 +1510,18 @@ DecodeDateTime(char **field, int *ftype, int nf,
if (fmask & DTK_M(MONTH)) if (fmask & DTK_M(MONTH))
{ {
if (tm->tm_mon < 1 || tm->tm_mon > 12) if (tm->tm_mon < 1 || tm->tm_mon > 12)
return -1; return DTERR_MD_FIELD_OVERFLOW;
} }
/* minimal check for valid day */ /* minimal check for valid day */
if (fmask & DTK_M(DAY)) if (fmask & DTK_M(DAY))
{ {
if (tm->tm_mday < 1 || tm->tm_mday > 31) if (tm->tm_mday < 1 || tm->tm_mday > 31)
return -1; return DTERR_MD_FIELD_OVERFLOW;
} }
if ((mer != HR24) && (tm->tm_hour > 12)) if ((mer != HR24) && (tm->tm_hour > 12))
return -1; return DTERR_FIELD_OVERFLOW;
if ((mer == AM) && (tm->tm_hour == 12)) if ((mer == AM) && (tm->tm_hour == 12))
tm->tm_hour = 0; tm->tm_hour = 0;
else if ((mer == PM) && (tm->tm_hour != 12)) else if ((mer == PM) && (tm->tm_hour != 12))
...@@ -1498,14 +1531,19 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1498,14 +1531,19 @@ DecodeDateTime(char **field, int *ftype, int nf,
if (*dtype == DTK_DATE) if (*dtype == DTK_DATE)
{ {
if ((fmask & DTK_DATE_M) != DTK_DATE_M) if ((fmask & DTK_DATE_M) != DTK_DATE_M)
return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1; {
if ((fmask & DTK_TIME_M) == DTK_TIME_M)
return 1;
return DTERR_BAD_FORMAT;
}
/* /*
* check for valid day of month, now that we know for sure the * Check for valid day of month, now that we know for sure the
* month and year... * month and year. Note we don't use MD_FIELD_OVERFLOW here,
* since it seems unlikely that "Feb 29" is a YMD-order error.
*/ */
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
return -1; return DTERR_FIELD_OVERFLOW;
/* timezone not specified? then find local timezone if possible */ /* timezone not specified? then find local timezone if possible */
if ((tzp != NULL) && (!(fmask & DTK_M(TZ)))) if ((tzp != NULL) && (!(fmask & DTK_M(TZ))))
...@@ -1515,14 +1553,14 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1515,14 +1553,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
* then error * then error
*/ */
if (fmask & DTK_M(DTZMOD)) if (fmask & DTK_M(DTZMOD))
return -1; return DTERR_BAD_FORMAT;
*tzp = DetermineLocalTimeZone(tm); *tzp = DetermineLocalTimeZone(tm);
} }
} }
return 0; return 0;
} /* DecodeDateTime() */ }
/* DetermineLocalTimeZone() /* DetermineLocalTimeZone()
...@@ -1673,6 +1711,8 @@ DetermineLocalTimeZone(struct tm * tm) ...@@ -1673,6 +1711,8 @@ DetermineLocalTimeZone(struct tm * tm)
/* DecodeTimeOnly() /* DecodeTimeOnly()
* Interpret parsed string as time fields only. * Interpret parsed string as time fields only.
* Returns 0 if successful, DTERR code if bogus input detected.
*
* Note that support for time zone is here for * Note that support for time zone is here for
* SQL92 TIME WITH TIME ZONE, but it reveals * SQL92 TIME WITH TIME ZONE, but it reveals
* bogosity with SQL92 date/time standards, since * bogosity with SQL92 date/time standards, since
...@@ -1691,6 +1731,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1691,6 +1731,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */ int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */
int i; int i;
int val; int val;
int dterr;
int is2digits = FALSE; int is2digits = FALSE;
int mer = HR24; int mer = HR24;
...@@ -1716,15 +1757,16 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1716,15 +1757,16 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
* time zones no matter what else! * time zones no matter what else!
*/ */
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
/* Under limited circumstances, we will accept a date... */ /* Under limited circumstances, we will accept a date... */
if ((i == 0) && (nf >= 2) if ((i == 0) && (nf >= 2)
&& ((ftype[nf - 1] == DTK_DATE) && ((ftype[nf - 1] == DTK_DATE)
|| (ftype[1] == DTK_TIME))) || (ftype[1] == DTK_TIME)))
{ {
if (DecodeDate(field[i], fmask, &tmask, tm) != 0) dterr = DecodeDate(field[i], fmask, &tmask, tm);
return -1; if (dterr)
return dterr;
} }
/* otherwise, this is a time and/or time zone */ /* otherwise, this is a time and/or time zone */
else else
...@@ -1739,34 +1781,40 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1739,34 +1781,40 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
* already... * already...
*/ */
if ((fmask & DTK_TIME_M) == DTK_TIME_M) if ((fmask & DTK_TIME_M) == DTK_TIME_M)
return -1; return DTERR_BAD_FORMAT;
/* /*
* Should not get here and fail. Sanity check * Should not get here and fail. Sanity check
* only... * only...
*/ */
if ((cp = strchr(field[i], '-')) == NULL) if ((cp = strchr(field[i], '-')) == NULL)
return -1; return DTERR_BAD_FORMAT;
/* Get the time zone from the end of the string */ /* Get the time zone from the end of the string */
if (DecodeTimezone(cp, tzp) != 0) dterr = DecodeTimezone(cp, tzp);
return -1; if (dterr)
return dterr;
*cp = '\0'; *cp = '\0';
/* /*
* Then read the rest of the field as a * Then read the rest of the field as a
* concatenated time * concatenated time
*/ */
if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M), dterr = DecodeNumberField(strlen(field[i]), field[i],
&tmask, tm, fsec, &is2digits)) < 0) (fmask | DTK_DATE_M),
return -1; &tmask, tm,
fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
tmask |= DTK_M(TZ); tmask |= DTK_M(TZ);
} }
else else
{ {
if (DecodePosixTimezone(field[i], tzp) != 0) dterr = DecodePosixTimezone(field[i], tzp);
return -1; if (dterr)
return dterr;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
tmask = DTK_M(TZ); tmask = DTK_M(TZ);
...@@ -1775,19 +1823,22 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1775,19 +1823,22 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
break; break;
case DTK_TIME: case DTK_TIME:
if (DecodeTime(field[i], (fmask | DTK_DATE_M), &tmask, tm, fsec) != 0) dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
return -1; &tmask, tm, fsec);
if (dterr)
return dterr;
break; break;
case DTK_TZ: case DTK_TZ:
if (tzp == NULL)
return -1;
{ {
int tz; int tz;
if (DecodeTimezone(field[i], &tz) != 0) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
dterr = DecodeTimezone(field[i], &tz);
if (dterr)
return dterr;
/* /*
* Already have a time zone? Then maybe this is the * Already have a time zone? Then maybe this is the
...@@ -1827,7 +1878,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1827,7 +1878,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case DTK_MONTH: case DTK_MONTH:
case DTK_DAY: case DTK_DAY:
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
default: default:
break; break;
} }
...@@ -1846,11 +1897,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1846,11 +1897,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case DTK_SECOND: case DTK_SECOND:
break; break;
default: default:
return 1; return DTERR_BAD_FORMAT;
break; break;
} }
else if (*cp != '\0') else if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
switch (ptype) switch (ptype)
{ {
...@@ -1902,7 +1953,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1902,7 +1953,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
frac = strtod(cp, &cp); frac = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000); *fsec = rint(frac * 1000000);
#else #else
...@@ -1913,8 +1964,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1913,8 +1964,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case DTK_TZ: case DTK_TZ:
tmask = DTK_M(TZ); tmask = DTK_M(TZ);
if (DecodeTimezone(field[i], tzp) != 0) dterr = DecodeTimezone(field[i], tzp);
return -1; if (dterr)
return dterr;
break; break;
case DTK_JULIAN: case DTK_JULIAN:
...@@ -1929,7 +1981,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1929,7 +1981,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
time = strtod(cp, &cp); time = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
tmask |= DTK_TIME_M; tmask |= DTK_TIME_M;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
...@@ -1944,16 +1996,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1944,16 +1996,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case DTK_TIME: case DTK_TIME:
/* previous field was "t" for ISO time */ /* previous field was "t" for ISO time */
if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M), dterr = DecodeNumberField(strlen(field[i]), field[i],
&tmask, tm, fsec, &is2digits)) < 0) (fmask | DTK_DATE_M),
return -1; &tmask, tm,
fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
if (tmask != DTK_TIME_M) if (tmask != DTK_TIME_M)
return -1; return DTERR_BAD_FORMAT;
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
break; break;
} }
...@@ -1977,8 +2033,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1977,8 +2033,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
*/ */
if ((i == 0) && ((nf >= 2) && (ftype[nf - 1] == DTK_DATE))) if ((i == 0) && ((nf >= 2) && (ftype[nf - 1] == DTK_DATE)))
{ {
if (DecodeDate(field[i], fmask, &tmask, tm) != 0) dterr = DecodeDate(field[i], fmask, &tmask, tm);
return -1; if (dterr)
return dterr;
} }
/* embedded decimal and several digits before? */ /* embedded decimal and several digits before? */
else if ((flen - strlen(cp)) > 2) else if ((flen - strlen(cp)) > 2)
...@@ -1988,26 +2045,37 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -1988,26 +2045,37 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
* Set the type field to allow decoding other * Set the type field to allow decoding other
* fields later. Example: 20011223 or 040506 * fields later. Example: 20011223 or 040506
*/ */
if ((ftype[i] = DecodeNumberField(flen, field[i], dterr = DecodeNumberField(flen, field[i],
(fmask | DTK_DATE_M), (fmask | DTK_DATE_M),
&tmask, tm, fsec, &is2digits)) < 0) &tmask, tm,
return -1; fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
} }
else else
return -1; return DTERR_BAD_FORMAT;
} }
else if (flen > 4) else if (flen > 4)
{ {
if ((ftype[i] = DecodeNumberField(flen, field[i], dterr = DecodeNumberField(flen, field[i],
(fmask | DTK_DATE_M), (fmask | DTK_DATE_M),
&tmask, tm, fsec, &is2digits)) < 0) &tmask, tm,
return -1; fsec, &is2digits);
if (dterr < 0)
return dterr;
ftype[i] = dterr;
} }
/* otherwise it is a single date/time field... */ /* otherwise it is a single date/time field... */
else if (DecodeNumber(flen, field[i], else
(fmask | DTK_DATE_M), {
&tmask, tm, fsec, &is2digits) != 0) dterr = DecodeNumber(flen, field[i],
return -1; (fmask | DTK_DATE_M),
&tmask, tm,
fsec, &is2digits);
if (dterr)
return dterr;
}
} }
break; break;
...@@ -2027,7 +2095,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2027,7 +2095,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("\"current\" is no longer supported"))); errmsg("\"current\" is no longer supported")));
return -1; return DTERR_BAD_FORMAT;
break; break;
case DTK_NOW: case DTK_NOW:
...@@ -2046,7 +2114,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2046,7 +2114,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
break; break;
...@@ -2060,7 +2128,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2060,7 +2128,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmask |= DTK_M(DTZ); tmask |= DTK_M(DTZ);
tm->tm_isdst = 1; tm->tm_isdst = 1;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp += val * 60; *tzp += val * 60;
break; break;
...@@ -2073,7 +2141,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2073,7 +2141,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmask |= DTK_M(TZ); tmask |= DTK_M(TZ);
tm->tm_isdst = 1; tm->tm_isdst = 1;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp = val * 60; *tzp = val * 60;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
break; break;
...@@ -2081,7 +2149,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2081,7 +2149,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case TZ: case TZ:
tm->tm_isdst = 0; tm->tm_isdst = 0;
if (tzp == NULL) if (tzp == NULL)
return -1; return DTERR_BAD_FORMAT;
*tzp = val * 60; *tzp = val * 60;
ftype[i] = DTK_TZ; ftype[i] = DTK_TZ;
break; break;
...@@ -2111,27 +2179,27 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2111,27 +2179,27 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
|| ((ftype[i + 1] != DTK_NUMBER) || ((ftype[i + 1] != DTK_NUMBER)
&& (ftype[i + 1] != DTK_TIME) && (ftype[i + 1] != DTK_TIME)
&& (ftype[i + 1] != DTK_DATE))) && (ftype[i + 1] != DTK_DATE)))
return -1; return DTERR_BAD_FORMAT;
ptype = val; ptype = val;
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
if (tmask & fmask) if (tmask & fmask)
return -1; return DTERR_BAD_FORMAT;
fmask |= tmask; fmask |= tmask;
} }
if ((mer != HR24) && (tm->tm_hour > 12)) if ((mer != HR24) && (tm->tm_hour > 12))
return -1; return DTERR_FIELD_OVERFLOW;
if ((mer == AM) && (tm->tm_hour == 12)) if ((mer == AM) && (tm->tm_hour == 12))
tm->tm_hour = 0; tm->tm_hour = 0;
else if ((mer == PM) && (tm->tm_hour != 12)) else if ((mer == PM) && (tm->tm_hour != 12))
...@@ -2142,17 +2210,17 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2142,17 +2210,17 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
|| (tm->tm_min < 0) || (tm->tm_min > 59) || (tm->tm_min < 0) || (tm->tm_min > 59)
|| (tm->tm_sec < 0) || (tm->tm_sec > 60) || (tm->tm_sec < 0) || (tm->tm_sec > 60)
|| (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000))) || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
return -1; return DTERR_FIELD_OVERFLOW;
#else #else
if ((tm->tm_hour < 0) || (tm->tm_hour > 23) if ((tm->tm_hour < 0) || (tm->tm_hour > 23)
|| (tm->tm_min < 0) || (tm->tm_min > 59) || (tm->tm_min < 0) || (tm->tm_min > 59)
|| (tm->tm_sec < 0) || (tm->tm_sec > 60) || (tm->tm_sec < 0) || (tm->tm_sec > 60)
|| (*fsec < 0) || (*fsec >= 1)) || (*fsec < 0) || (*fsec >= 1))
return -1; return DTERR_FIELD_OVERFLOW;
#endif #endif
if ((fmask & DTK_TIME_M) != DTK_TIME_M) if ((fmask & DTK_TIME_M) != DTK_TIME_M)
return -1; return DTERR_BAD_FORMAT;
/* timezone not specified? then find local timezone if possible */ /* timezone not specified? then find local timezone if possible */
if ((tzp != NULL) && (!(fmask & DTK_M(TZ)))) if ((tzp != NULL) && (!(fmask & DTK_M(TZ))))
...@@ -2165,7 +2233,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2165,7 +2233,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
* error * error
*/ */
if (fmask & DTK_M(DTZMOD)) if (fmask & DTK_M(DTZMOD))
return -1; return DTERR_BAD_FORMAT;
if ((fmask & DTK_DATE_M) == 0) if ((fmask & DTK_DATE_M) == 0)
GetCurrentDateTime(tmp); GetCurrentDateTime(tmp);
...@@ -2183,20 +2251,22 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2183,20 +2251,22 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
} }
return 0; return 0;
} /* DecodeTimeOnly() */ }
/* DecodeDate() /* DecodeDate()
* Decode date string which includes delimiters. * Decode date string which includes delimiters.
* Return 0 if okay, a DTERR code if not.
*
* Insist on a complete set of fields. * Insist on a complete set of fields.
*/ */
static int static int
DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
{ {
fsec_t fsec; fsec_t fsec;
int nf = 0; int nf = 0;
int i, int i,
len; len;
int dterr;
int bc = FALSE; int bc = FALSE;
int is2digits = FALSE; int is2digits = FALSE;
int type, int type,
...@@ -2232,7 +2302,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -2232,7 +2302,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
#if 0 #if 0
/* don't allow too many fields */ /* don't allow too many fields */
if (nf > 3) if (nf > 3)
return -1; return DTERR_BAD_FORMAT;
#endif #endif
*tmask = 0; *tmask = 0;
...@@ -2258,10 +2328,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -2258,10 +2328,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
if (fmask & dmask) if (fmask & dmask)
return -1; return DTERR_BAD_FORMAT;
fmask |= dmask; fmask |= dmask;
*tmask |= dmask; *tmask |= dmask;
...@@ -2278,20 +2348,23 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -2278,20 +2348,23 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
continue; continue;
if ((len = strlen(field[i])) <= 0) if ((len = strlen(field[i])) <= 0)
return -1; return DTERR_BAD_FORMAT;
if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits) != 0) dterr = DecodeNumber(len, field[i], fmask,
return -1; &dmask, tm,
&fsec, &is2digits);
if (dterr)
return dterr;
if (fmask & dmask) if (fmask & dmask)
return -1; return DTERR_BAD_FORMAT;
fmask |= dmask; fmask |= dmask;
*tmask |= dmask; *tmask |= dmask;
} }
if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
return -1; return DTERR_BAD_FORMAT;
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
if (bc) if (bc)
...@@ -2321,19 +2394,24 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -2321,19 +2394,24 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
/* check for valid month */ /* check for valid month */
if (tm->tm_mon < 1 || tm->tm_mon > 12) if (tm->tm_mon < 1 || tm->tm_mon > 12)
return -1; return DTERR_MD_FIELD_OVERFLOW;
/* check for valid day */ /* check for valid day */
if (tm->tm_mday < 1 || if (tm->tm_mday < 1 || tm->tm_mday > 31)
tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) return DTERR_MD_FIELD_OVERFLOW;
return -1;
/* We don't want to hint about DateStyle for Feb 29 */
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
return DTERR_FIELD_OVERFLOW;
return 0; return 0;
} /* DecodeDate() */ }
/* DecodeTime() /* DecodeTime()
* Decode time string which includes delimiters. * Decode time string which includes delimiters.
* Return 0 if okay, a DTERR code if not.
*
* Only check the lower limit on hours, since this same code * Only check the lower limit on hours, since this same code
* can be used to represent time spans. * can be used to represent time spans.
*/ */
...@@ -2346,7 +2424,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) ...@@ -2346,7 +2424,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
tm->tm_hour = strtol(str, &cp, 10); tm->tm_hour = strtol(str, &cp, 10);
if (*cp != ':') if (*cp != ':')
return -1; return DTERR_BAD_FORMAT;
str = cp + 1; str = cp + 1;
tm->tm_min = strtol(str, &cp, 10); tm->tm_min = strtol(str, &cp, 10);
if (*cp == '\0') if (*cp == '\0')
...@@ -2355,7 +2433,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) ...@@ -2355,7 +2433,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
*fsec = 0; *fsec = 0;
} }
else if (*cp != ':') else if (*cp != ':')
return -1; return DTERR_BAD_FORMAT;
else else
{ {
str = cp + 1; str = cp + 1;
...@@ -2369,7 +2447,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) ...@@ -2369,7 +2447,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
str = cp; str = cp;
frac = strtod(str, &cp); frac = strtod(str, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000); *fsec = rint(frac * 1000000);
#else #else
...@@ -2377,7 +2455,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) ...@@ -2377,7 +2455,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
#endif #endif
} }
else else
return -1; return DTERR_BAD_FORMAT;
} }
/* do a sanity check */ /* do a sanity check */
...@@ -2386,21 +2464,22 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) ...@@ -2386,21 +2464,22 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
|| (tm->tm_min < 0) || (tm->tm_min > 59) || (tm->tm_min < 0) || (tm->tm_min > 59)
|| (tm->tm_sec < 0) || (tm->tm_sec > 60) || (tm->tm_sec < 0) || (tm->tm_sec > 60)
|| (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000))) || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
return -1; return DTERR_FIELD_OVERFLOW;
#else #else
if ((tm->tm_hour < 0) if ((tm->tm_hour < 0)
|| (tm->tm_min < 0) || (tm->tm_min > 59) || (tm->tm_min < 0) || (tm->tm_min > 59)
|| (tm->tm_sec < 0) || (tm->tm_sec > 60) || (tm->tm_sec < 0) || (tm->tm_sec > 60)
|| (*fsec < 0) || (*fsec >= 1)) || (*fsec < 0) || (*fsec >= 1))
return -1; return DTERR_FIELD_OVERFLOW;
#endif #endif
return 0; return 0;
} /* DecodeTime() */ }
/* DecodeNumber() /* DecodeNumber()
* Interpret plain numeric field as a date value in context. * Interpret plain numeric field as a date value in context.
* Return 0 if okay, a DTERR code if not.
*/ */
static int static int
DecodeNumber(int flen, char *str, int fmask, DecodeNumber(int flen, char *str, int fmask,
...@@ -2408,12 +2487,13 @@ DecodeNumber(int flen, char *str, int fmask, ...@@ -2408,12 +2487,13 @@ DecodeNumber(int flen, char *str, int fmask,
{ {
int val; int val;
char *cp; char *cp;
int dterr;
*tmask = 0; *tmask = 0;
val = strtol(str, &cp, 10); val = strtol(str, &cp, 10);
if (cp == str) if (cp == str)
return -1; return DTERR_BAD_FORMAT;
if (*cp == '.') if (*cp == '.')
{ {
...@@ -2425,15 +2505,18 @@ DecodeNumber(int flen, char *str, int fmask, ...@@ -2425,15 +2505,18 @@ DecodeNumber(int flen, char *str, int fmask,
*/ */
if ((cp - str) > 2) if ((cp - str) > 2)
{ {
if (DecodeNumberField(flen, str, (fmask | DTK_DATE_M), dterr = DecodeNumberField(flen, str,
tmask, tm, fsec, is2digits) < 0) (fmask | DTK_DATE_M),
return -1; tmask, tm,
fsec, is2digits);
if (dterr < 0)
return dterr;
return 0; return 0;
} }
frac = strtod(cp, &cp); frac = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000); *fsec = rint(frac * 1000000);
#else #else
...@@ -2441,7 +2524,7 @@ DecodeNumber(int flen, char *str, int fmask, ...@@ -2441,7 +2524,7 @@ DecodeNumber(int flen, char *str, int fmask,
#endif #endif
} }
else if (*cp != '\0') else if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
/* Special case for day of year */ /* Special case for day of year */
if ((flen == 3) && if ((flen == 3) &&
...@@ -2515,14 +2598,16 @@ DecodeNumber(int flen, char *str, int fmask, ...@@ -2515,14 +2598,16 @@ DecodeNumber(int flen, char *str, int fmask,
case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)): case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
/* we have all the date, so it must be a time field */ /* we have all the date, so it must be a time field */
if (DecodeNumberField(flen, str, fmask, dterr = DecodeNumberField(flen, str, fmask,
tmask, tm, fsec, is2digits) < 0) tmask, tm,
return -1; fsec, is2digits);
if (dterr < 0)
return dterr;
return 0; return 0;
default: default:
/* Anything else is bogus input */ /* Anything else is bogus input */
return -1; return DTERR_BAD_FORMAT;
} }
/* /*
...@@ -2538,12 +2623,14 @@ DecodeNumber(int flen, char *str, int fmask, ...@@ -2538,12 +2623,14 @@ DecodeNumber(int flen, char *str, int fmask,
/* DecodeNumberField() /* DecodeNumberField()
* Interpret numeric string as a concatenated date or time field. * Interpret numeric string as a concatenated date or time field.
* Return a DTK token (>= 0) if successful, a DTERR code (< 0) if not.
*
* Use the context of previously decoded fields to help with * Use the context of previously decoded fields to help with
* the interpretation. * the interpretation.
*/ */
static int static int
DecodeNumberField(int len, char *str, int fmask, DecodeNumberField(int len, char *str, int fmask,
int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits) int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits)
{ {
char *cp; char *cp;
...@@ -2623,14 +2710,14 @@ DecodeNumberField(int len, char *str, int fmask, ...@@ -2623,14 +2710,14 @@ DecodeNumberField(int len, char *str, int fmask,
} }
} }
return -1; return DTERR_BAD_FORMAT;
} /* DecodeNumberField() */ }
/* DecodeTimezone() /* DecodeTimezone()
* Interpret string as a numeric timezone. * Interpret string as a numeric timezone.
* *
* Return 0 if okay (and set *tzp), nonzero if not okay. * Return 0 if okay (and set *tzp), a DTERR code if not okay.
* *
* NB: this must *not* ereport on failure; see commands/variable.c. * NB: this must *not* ereport on failure; see commands/variable.c.
* *
...@@ -2644,11 +2731,10 @@ DecodeTimezone(char *str, int *tzp) ...@@ -2644,11 +2731,10 @@ DecodeTimezone(char *str, int *tzp)
int hr, int hr,
min; min;
char *cp; char *cp;
int len;
/* leading character must be "+" or "-" */ /* leading character must be "+" or "-" */
if (*str != '+' && *str != '-') if (*str != '+' && *str != '-')
return -1; return DTERR_BAD_FORMAT;
hr = strtol((str + 1), &cp, 10); hr = strtol((str + 1), &cp, 10);
...@@ -2656,28 +2742,30 @@ DecodeTimezone(char *str, int *tzp) ...@@ -2656,28 +2742,30 @@ DecodeTimezone(char *str, int *tzp)
if (*cp == ':') if (*cp == ':')
min = strtol((cp + 1), &cp, 10); min = strtol((cp + 1), &cp, 10);
/* otherwise, might have run things together... */ /* otherwise, might have run things together... */
else if ((*cp == '\0') && ((len = strlen(str)) > 3)) else if ((*cp == '\0') && (strlen(str) > 3))
{ {
min = strtol((str + len - 2), &cp, 10); min = hr % 100;
if ((min < 0) || (min >= 60)) hr = hr / 100;
return -1;
*(str + len - 2) = '\0';
hr = strtol((str + 1), &cp, 10);
if ((hr < 0) || (hr > 13))
return -1;
} }
else else
min = 0; min = 0;
tz = (hr * 60 + min) * 60; if ((hr < 0) || (hr > 13))
return DTERR_TZDISP_OVERFLOW;
if ((min < 0) || (min >= 60))
return DTERR_TZDISP_OVERFLOW;
tz = (hr * 60 + min) * 60;
if (*str == '-') if (*str == '-')
tz = -tz; tz = -tz;
*tzp = -tz; *tzp = -tz;
return *cp != '\0';
} /* DecodeTimezone() */ if (*cp != '\0')
return DTERR_BAD_FORMAT;
return 0;
}
/* DecodePosixTimezone() /* DecodePosixTimezone()
...@@ -2687,7 +2775,7 @@ DecodeTimezone(char *str, int *tzp) ...@@ -2687,7 +2775,7 @@ DecodeTimezone(char *str, int *tzp)
* PST * PST
* - thomas 2000-03-15 * - thomas 2000-03-15
* *
* Return 0 if okay (and set *tzp), nonzero if not okay. * Return 0 if okay (and set *tzp), a DTERR code if not okay.
* *
* NB: this must *not* ereport on failure; see commands/variable.c. * NB: this must *not* ereport on failure; see commands/variable.c.
*/ */
...@@ -2697,6 +2785,7 @@ DecodePosixTimezone(char *str, int *tzp) ...@@ -2697,6 +2785,7 @@ DecodePosixTimezone(char *str, int *tzp)
int val, int val,
tz; tz;
int type; int type;
int dterr;
char *cp; char *cp;
char delim; char delim;
...@@ -2708,8 +2797,9 @@ DecodePosixTimezone(char *str, int *tzp) ...@@ -2708,8 +2797,9 @@ DecodePosixTimezone(char *str, int *tzp)
/* decode offset, if present */ /* decode offset, if present */
if (*cp) if (*cp)
{ {
if (DecodeTimezone(cp, &tz) != 0) dterr = DecodeTimezone(cp, &tz);
return -1; if (dterr)
return dterr;
} }
else else
tz = 0; tz = 0;
...@@ -2728,11 +2818,11 @@ DecodePosixTimezone(char *str, int *tzp) ...@@ -2728,11 +2818,11 @@ DecodePosixTimezone(char *str, int *tzp)
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
return 0; return 0;
} /* DecodePosixTimezone() */ }
/* DecodeSpecial() /* DecodeSpecial()
...@@ -2786,12 +2876,12 @@ DecodeSpecial(int field, char *lowtoken, int *val) ...@@ -2786,12 +2876,12 @@ DecodeSpecial(int field, char *lowtoken, int *val)
} }
return type; return type;
} /* DecodeSpecial() */ }
/* DecodeInterval() /* DecodeInterval()
* Interpret previously parsed fields for general time interval. * Interpret previously parsed fields for general time interval.
* Return 0 if decoded and -1 if problems. * Returns 0 if successful, DTERR code if bogus input detected.
* *
* Allow "date" field DTK_DATE since this could be just * Allow "date" field DTK_DATE since this could be just
* an unsigned floating point number. - thomas 1997-11-16 * an unsigned floating point number. - thomas 1997-11-16
...@@ -2803,12 +2893,12 @@ int ...@@ -2803,12 +2893,12 @@ int
DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec) DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
{ {
int is_before = FALSE; int is_before = FALSE;
char *cp; char *cp;
int fmask = 0, int fmask = 0,
tmask, tmask,
type; type;
int i; int i;
int dterr;
int val; int val;
double fval; double fval;
...@@ -2829,8 +2919,9 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -2829,8 +2919,9 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
switch (ftype[i]) switch (ftype[i])
{ {
case DTK_TIME: case DTK_TIME:
if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
return -1; if (dterr)
return dterr;
type = DTK_DAY; type = DTK_DAY;
break; break;
...@@ -2850,8 +2941,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -2850,8 +2941,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
cp = field[i] + 1; cp = field[i] + 1;
while ((*cp != '\0') && (*cp != ':') && (*cp != '.')) while ((*cp != '\0') && (*cp != ':') && (*cp != '.'))
cp++; cp++;
if ((*cp == ':') if ((*cp == ':') &&
&& (DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0)) (DecodeTime(field[i] + 1, fmask, &tmask, tm, fsec) == 0))
{ {
if (*field[i] == '-') if (*field[i] == '-')
{ {
...@@ -2903,7 +2994,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -2903,7 +2994,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
{ {
fval = strtod(cp, &cp); fval = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return DTERR_BAD_FORMAT;
if (val < 0) if (val < 0)
fval = -(fval); fval = -(fval);
...@@ -2911,7 +3002,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -2911,7 +3002,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
else if (*cp == '\0') else if (*cp == '\0')
fval = 0; fval = 0;
else else
return -1; return DTERR_BAD_FORMAT;
tmask = 0; /* DTK_M(type); */ tmask = 0; /* DTK_M(type); */
...@@ -3062,7 +3153,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -3062,7 +3153,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
break; break;
...@@ -3090,16 +3181,16 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -3090,16 +3181,16 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
break; break;
default: default:
return -1; return DTERR_BAD_FORMAT;
} }
if (tmask & fmask) if (tmask & fmask)
return -1; return DTERR_BAD_FORMAT;
fmask |= tmask; fmask |= tmask;
} }
...@@ -3128,8 +3219,11 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse ...@@ -3128,8 +3219,11 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
} }
/* ensure that at least one time field has been found */ /* ensure that at least one time field has been found */
return (fmask != 0) ? 0 : -1; if (fmask == 0)
} /* DecodeInterval() */ return DTERR_BAD_FORMAT;
return 0;
}
/* DecodeUnits() /* DecodeUnits()
...@@ -3165,6 +3259,57 @@ DecodeUnits(int field, char *lowtoken, int *val) ...@@ -3165,6 +3259,57 @@ DecodeUnits(int field, char *lowtoken, int *val)
return type; return type;
} /* DecodeUnits() */ } /* DecodeUnits() */
/*
* Report an error detected by one of the datetime input processing routines.
*
* dterr is the error code, str is the original input string, datatype is
* the name of the datatype we were trying to accept.
*
* Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
* DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
* separate SQLSTATE codes, so ...
*/
void
DateTimeParseError(int dterr, const char *str, const char *datatype)
{
switch (dterr)
{
case DTERR_FIELD_OVERFLOW:
ereport(ERROR,
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
errmsg("date/time field value out of range: \"%s\"",
str)));
break;
case DTERR_MD_FIELD_OVERFLOW:
/* <nanny>same as above, but add hint about DateStyle</nanny> */
ereport(ERROR,
(errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
errmsg("date/time field value out of range: \"%s\"",
str),
errhint("Perhaps you need a different DateStyle setting.")));
break;
case DTERR_INTERVAL_OVERFLOW:
ereport(ERROR,
(errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
errmsg("interval field value out of range: \"%s\"",
str)));
break;
case DTERR_TZDISP_OVERFLOW:
ereport(ERROR,
(errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
errmsg("time zone displacement out of range: \"%s\"",
str)));
break;
case DTERR_BAD_FORMAT:
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
/* translator: first %s is datatype name */
errmsg("invalid input syntax for %s: \"%s\"",
datatype, str)));
break;
}
}
/* datebsearch() /* datebsearch()
* Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.114 2003/08/17 19:58:05 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.115 2003/08/27 23:29:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -364,6 +364,7 @@ abstimein(PG_FUNCTION_ARGS) ...@@ -364,6 +364,7 @@ abstimein(PG_FUNCTION_ARGS)
int tz = 0; int tz = 0;
struct tm date, struct tm date,
*tm = &date; *tm = &date;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
int dtype; int dtype;
...@@ -371,15 +372,13 @@ abstimein(PG_FUNCTION_ARGS) ...@@ -371,15 +372,13 @@ abstimein(PG_FUNCTION_ARGS)
ftype[MAXDATEFIELDS]; ftype[MAXDATEFIELDS];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for abstime: \"%s\"", str))); dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) if (dterr != 0)
ereport(ERROR, DateTimeParseError(dterr, str, "abstime");
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for abstime: \"%s\"", str)));
switch (dtype) switch (dtype)
{ {
...@@ -768,21 +767,24 @@ reltimein(PG_FUNCTION_ARGS) ...@@ -768,21 +767,24 @@ reltimein(PG_FUNCTION_ARGS)
*tm = &tt; *tm = &tt;
fsec_t fsec; fsec_t fsec;
int dtype; int dtype;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int nf, int nf,
ftype[MAXDATEFIELDS]; ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1]; char lowstr[MAXDATELEN + 1];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for reltime: \"%s\"", str))); dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
|| (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0)) if (dterr != 0)
ereport(ERROR, {
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), if (dterr == DTERR_FIELD_OVERFLOW)
errmsg("invalid input syntax for reltime: \"%s\"", str))); dterr = DTERR_INTERVAL_OVERFLOW;
DateTimeParseError(dterr, str, "reltime");
}
switch (dtype) switch (dtype)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.93 2003/08/26 21:31:11 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.94 2003/08/27 23:29:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -77,22 +77,19 @@ timestamp_in(PG_FUNCTION_ARGS) ...@@ -77,22 +77,19 @@ timestamp_in(PG_FUNCTION_ARGS)
int tz; int tz;
int dtype; int dtype;
int nf; int nf;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + MAXDATEFIELDS]; char lowstr[MAXDATELEN + MAXDATEFIELDS];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for timestamp: \"%s\"", dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
str))); if (dterr == 0)
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) if (dterr != 0)
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) DateTimeParseError(dterr, str, "timestamp");
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for timestamp: \"%s\"",
str)));
switch (dtype) switch (dtype)
{ {
...@@ -306,22 +303,19 @@ timestamptz_in(PG_FUNCTION_ARGS) ...@@ -306,22 +303,19 @@ timestamptz_in(PG_FUNCTION_ARGS)
int tz; int tz;
int dtype; int dtype;
int nf; int nf;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + MAXDATEFIELDS]; char lowstr[MAXDATELEN + MAXDATEFIELDS];
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for timestamp with time zone: \"%s\"", dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
str))); if (dterr == 0)
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) if (dterr != 0)
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) DateTimeParseError(dterr, str, "timestamp with time zone");
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for timestamp with time zone: \"%s\"",
str)));
switch (dtype) switch (dtype)
{ {
...@@ -468,6 +462,7 @@ interval_in(PG_FUNCTION_ARGS) ...@@ -468,6 +462,7 @@ interval_in(PG_FUNCTION_ARGS)
*tm = &tt; *tm = &tt;
int dtype; int dtype;
int nf; int nf;
int dterr;
char *field[MAXDATEFIELDS]; char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + MAXDATEFIELDS]; char lowstr[MAXDATELEN + MAXDATEFIELDS];
...@@ -481,17 +476,17 @@ interval_in(PG_FUNCTION_ARGS) ...@@ -481,17 +476,17 @@ interval_in(PG_FUNCTION_ARGS)
fsec = 0; fsec = 0;
if (strlen(str) >= sizeof(lowstr)) if (strlen(str) >= sizeof(lowstr))
ereport(ERROR, dterr = DTERR_BAD_FORMAT;
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), else
errmsg("invalid input syntax for interval: \"%s\"", dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);
str))); if (dterr == 0)
dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) if (dterr != 0)
|| (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0)) {
ereport(ERROR, if (dterr == DTERR_FIELD_OVERFLOW)
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), dterr = DTERR_INTERVAL_OVERFLOW;
errmsg("invalid input syntax for interval: \"%s\"", DateTimeParseError(dterr, str, "interval");
str))); }
result = (Interval *) palloc(sizeof(Interval)); result = (Interval *) palloc(sizeof(Interval));
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: datetime.h,v 1.44 2003/08/05 18:30:21 tgl Exp $ * $Id: datetime.h,v 1.45 2003/08/27 23:29:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -204,7 +204,7 @@ typedef struct ...@@ -204,7 +204,7 @@ typedef struct
*/ */
#define FMODULO(t,q,u) \ #define FMODULO(t,q,u) \
do { \ do { \
q = ((t < 0) ? ceil(t / u): floor(t / u)); \ q = ((t < 0) ? ceil(t / u) : floor(t / u)); \
if (q != 0) t -= rint(q * u); \ if (q != 0) t -= rint(q * u); \
} while(0) } while(0)
...@@ -222,7 +222,7 @@ do { \ ...@@ -222,7 +222,7 @@ do { \
#else #else
#define TMODULO(t,q,u) \ #define TMODULO(t,q,u) \
do { \ do { \
q = ((t < 0) ? ceil(t / u): floor(t / u)); \ q = ((t < 0) ? ceil(t / u) : floor(t / u)); \
if (q != 0) t -= rint(q * u); \ if (q != 0) t -= rint(q * u); \
} while(0) } while(0)
#endif #endif
...@@ -253,6 +253,15 @@ extern int day_tab[2][13]; ...@@ -253,6 +253,15 @@ extern int day_tab[2][13];
|| (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY))))) \ || (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY))))) \
&& ((y) < JULIAN_MAXYEAR)) && ((y) < JULIAN_MAXYEAR))
/* Julian-date equivalents of Day 0 in Unix and Postgres reckoning */
#define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */
#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
/*
* Info about limits of the Unix time_t data type. We assume that time_t
* is a signed int32 with origin 1970-01-01. Note this is only relevant
* when we use the C library's time routines for timezone processing.
*/
#define UTIME_MINYEAR (1901) #define UTIME_MINYEAR (1901)
#define UTIME_MINMONTH (12) #define UTIME_MINMONTH (12)
#define UTIME_MINDAY (14) #define UTIME_MINDAY (14)
...@@ -267,9 +276,17 @@ extern int day_tab[2][13]; ...@@ -267,9 +276,17 @@ extern int day_tab[2][13];
|| (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \ || (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \
|| (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY)))))) || (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY))))))
/* Julian-date equivalents of Day 0 in Unix and Postgres reckoning */ /*
#define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */ * Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc)
#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */ * return zero or a positive value on success. On failure, they return
* one of these negative code values. DateTimeParseError may be used to
* produce a correct ereport.
*/
#define DTERR_BAD_FORMAT (-1)
#define DTERR_FIELD_OVERFLOW (-2)
#define DTERR_MD_FIELD_OVERFLOW (-3) /* triggers hint about DateStyle */
#define DTERR_INTERVAL_OVERFLOW (-4)
#define DTERR_TZDISP_OVERFLOW (-5)
extern void GetCurrentDateTime(struct tm * tm); extern void GetCurrentDateTime(struct tm * tm);
...@@ -283,14 +300,14 @@ extern int ParseDateTime(const char *timestr, char *lowstr, ...@@ -283,14 +300,14 @@ extern int ParseDateTime(const char *timestr, char *lowstr,
extern int DecodeDateTime(char **field, int *ftype, extern int DecodeDateTime(char **field, int *ftype,
int nf, int *dtype, int nf, int *dtype,
struct tm * tm, fsec_t *fsec, int *tzp); struct tm * tm, fsec_t *fsec, int *tzp);
extern int DecodeTimeOnly(char **field, int *ftype, extern int DecodeTimeOnly(char **field, int *ftype,
int nf, int *dtype, int nf, int *dtype,
struct tm * tm, fsec_t *fsec, int *tzp); struct tm * tm, fsec_t *fsec, int *tzp);
extern int DecodeInterval(char **field, int *ftype, extern int DecodeInterval(char **field, int *ftype,
int nf, int *dtype, int nf, int *dtype,
struct tm * tm, fsec_t *fsec); struct tm * tm, fsec_t *fsec);
extern void DateTimeParseError(int dterr, const char *str,
const char *datatype);
extern int DetermineLocalTimeZone(struct tm * tm); extern int DetermineLocalTimeZone(struct tm * tm);
......
...@@ -28,9 +28,10 @@ INSERT INTO ABSTIME_TBL (f1) VALUES (abstime '-infinity'); ...@@ -28,9 +28,10 @@ INSERT INTO ABSTIME_TBL (f1) VALUES (abstime '-infinity');
INSERT INTO ABSTIME_TBL (f1) VALUES (abstime 'May 10, 1947 23:59:12'); INSERT INTO ABSTIME_TBL (f1) VALUES (abstime 'May 10, 1947 23:59:12');
-- what happens if we specify slightly misformatted abstime? -- what happens if we specify slightly misformatted abstime?
INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 35, 1946 10:00:00'); INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 35, 1946 10:00:00');
ERROR: invalid input syntax for abstime: "Feb 35, 1946 10:00:00" ERROR: date/time field value out of range: "Feb 35, 1946 10:00:00"
HINT: Perhaps you need a different DateStyle setting.
INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 28, 1984 25:08:10'); INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 28, 1984 25:08:10');
ERROR: invalid input syntax for abstime: "Feb 28, 1984 25:08:10" ERROR: date/time field value out of range: "Feb 28, 1984 25:08:10"
-- badly formatted abstimes: these should result in invalid abstimes -- badly formatted abstimes: these should result in invalid abstimes
INSERT INTO ABSTIME_TBL (f1) VALUES ('bad date format'); INSERT INTO ABSTIME_TBL (f1) VALUES ('bad date format');
ERROR: invalid input syntax for abstime: "bad date format" ERROR: invalid input syntax for abstime: "bad date format"
......
...@@ -28,9 +28,10 @@ INSERT INTO ABSTIME_TBL (f1) VALUES (abstime '-infinity'); ...@@ -28,9 +28,10 @@ INSERT INTO ABSTIME_TBL (f1) VALUES (abstime '-infinity');
INSERT INTO ABSTIME_TBL (f1) VALUES (abstime 'May 10, 1947 23:59:12'); INSERT INTO ABSTIME_TBL (f1) VALUES (abstime 'May 10, 1947 23:59:12');
-- what happens if we specify slightly misformatted abstime? -- what happens if we specify slightly misformatted abstime?
INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 35, 1946 10:00:00'); INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 35, 1946 10:00:00');
ERROR: invalid input syntax for abstime: "Feb 35, 1946 10:00:00" ERROR: date/time field value out of range: "Feb 35, 1946 10:00:00"
HINT: Perhaps you need a different DateStyle setting.
INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 28, 1984 25:08:10'); INSERT INTO ABSTIME_TBL (f1) VALUES ('Feb 28, 1984 25:08:10');
ERROR: invalid input syntax for abstime: "Feb 28, 1984 25:08:10" ERROR: date/time field value out of range: "Feb 28, 1984 25:08:10"
-- badly formatted abstimes: these should result in invalid abstimes -- badly formatted abstimes: these should result in invalid abstimes
INSERT INTO ABSTIME_TBL (f1) VALUES ('bad date format'); INSERT INTO ABSTIME_TBL (f1) VALUES ('bad date format');
ERROR: invalid input syntax for abstime: "bad date format" ERROR: invalid input syntax for abstime: "bad date format"
......
...@@ -10,7 +10,7 @@ INSERT INTO DATE_TBL VALUES ('1996-03-01'); ...@@ -10,7 +10,7 @@ INSERT INTO DATE_TBL VALUES ('1996-03-01');
INSERT INTO DATE_TBL VALUES ('1996-03-02'); INSERT INTO DATE_TBL VALUES ('1996-03-02');
INSERT INTO DATE_TBL VALUES ('1997-02-28'); INSERT INTO DATE_TBL VALUES ('1997-02-28');
INSERT INTO DATE_TBL VALUES ('1997-02-29'); INSERT INTO DATE_TBL VALUES ('1997-02-29');
ERROR: invalid input syntax for date: "1997-02-29" ERROR: date/time field value out of range: "1997-02-29"
INSERT INTO DATE_TBL VALUES ('1997-03-01'); INSERT INTO DATE_TBL VALUES ('1997-03-01');
INSERT INTO DATE_TBL VALUES ('1997-03-02'); INSERT INTO DATE_TBL VALUES ('1997-03-02');
INSERT INTO DATE_TBL VALUES ('2000-04-01'); INSERT INTO DATE_TBL VALUES ('2000-04-01');
......
...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08'; ...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08';
-- should fail in mdy mode: -- should fail in mdy mode:
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
ERROR: invalid input syntax for timestamp with time zone: "27/12/2001 04:05:06.789-08" ERROR: date/time field value out of range: "27/12/2001 04:05:06.789-08"
HINT: Perhaps you need a different DateStyle setting.
set datestyle to dmy; set datestyle to dmy;
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
timestamptz timestamptz
......
...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08'; ...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08';
-- should fail in mdy mode: -- should fail in mdy mode:
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
ERROR: invalid input syntax for timestamp with time zone: "27/12/2001 04:05:06.789-08" ERROR: date/time field value out of range: "27/12/2001 04:05:06.789-08"
HINT: Perhaps you need a different DateStyle setting.
set datestyle to dmy; set datestyle to dmy;
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
timestamptz timestamptz
......
...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08'; ...@@ -81,7 +81,8 @@ SELECT timestamp with time zone '12/27/2001 04:05:06.789-08';
-- should fail in mdy mode: -- should fail in mdy mode:
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
ERROR: invalid input syntax for timestamp with time zone: "27/12/2001 04:05:06.789-08" ERROR: date/time field value out of range: "27/12/2001 04:05:06.789-08"
HINT: Perhaps you need a different DateStyle setting.
set datestyle to dmy; set datestyle to dmy;
SELECT timestamp with time zone '27/12/2001 04:05:06.789-08'; SELECT timestamp with time zone '27/12/2001 04:05:06.789-08';
timestamptz timestamptz
......
...@@ -128,7 +128,7 @@ INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 1996'); ...@@ -128,7 +128,7 @@ INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 1996');
INSERT INTO TIMESTAMP_TBL VALUES ('Jan 01 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Jan 01 17:32:01 1997');
INSERT INTO TIMESTAMP_TBL VALUES ('Feb 28 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Feb 28 17:32:01 1997');
INSERT INTO TIMESTAMP_TBL VALUES ('Feb 29 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Feb 29 17:32:01 1997');
ERROR: invalid input syntax for timestamp: "Feb 29 17:32:01 1997" ERROR: date/time field value out of range: "Feb 29 17:32:01 1997"
INSERT INTO TIMESTAMP_TBL VALUES ('Mar 01 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Mar 01 17:32:01 1997');
INSERT INTO TIMESTAMP_TBL VALUES ('Dec 30 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Dec 30 17:32:01 1997');
INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 1997'); INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 1997');
...@@ -138,7 +138,7 @@ INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 2000'); ...@@ -138,7 +138,7 @@ INSERT INTO TIMESTAMP_TBL VALUES ('Dec 31 17:32:01 2000');
INSERT INTO TIMESTAMP_TBL VALUES ('Jan 01 17:32:01 2001'); INSERT INTO TIMESTAMP_TBL VALUES ('Jan 01 17:32:01 2001');
-- Currently unsupported syntax and ranges -- Currently unsupported syntax and ranges
INSERT INTO TIMESTAMP_TBL VALUES ('Feb 16 17:32:01 -0097'); INSERT INTO TIMESTAMP_TBL VALUES ('Feb 16 17:32:01 -0097');
ERROR: invalid input syntax for timestamp: "Feb 16 17:32:01 -0097" ERROR: time zone displacement out of range: "Feb 16 17:32:01 -0097"
INSERT INTO TIMESTAMP_TBL VALUES ('Feb 16 17:32:01 5097 BC'); INSERT INTO TIMESTAMP_TBL VALUES ('Feb 16 17:32:01 5097 BC');
ERROR: timestamp out of range: "Feb 16 17:32:01 5097 BC" ERROR: timestamp out of range: "Feb 16 17:32:01 5097 BC"
SELECT '' AS "64", d1 FROM TIMESTAMP_TBL; SELECT '' AS "64", d1 FROM TIMESTAMP_TBL;
......
...@@ -123,7 +123,7 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 1996'); ...@@ -123,7 +123,7 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 1996');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Jan 01 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Jan 01 17:32:01 1997');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 28 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 28 17:32:01 1997');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 29 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 29 17:32:01 1997');
ERROR: invalid input syntax for timestamp with time zone: "Feb 29 17:32:01 1997" ERROR: date/time field value out of range: "Feb 29 17:32:01 1997"
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Mar 01 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Mar 01 17:32:01 1997');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 30 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 30 17:32:01 1997');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 1997'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 1997');
...@@ -133,7 +133,7 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 2000'); ...@@ -133,7 +133,7 @@ INSERT INTO TIMESTAMPTZ_TBL VALUES ('Dec 31 17:32:01 2000');
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Jan 01 17:32:01 2001'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Jan 01 17:32:01 2001');
-- Currently unsupported syntax and ranges -- Currently unsupported syntax and ranges
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 16 17:32:01 -0097'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 16 17:32:01 -0097');
ERROR: invalid input syntax for timestamp with time zone: "Feb 16 17:32:01 -0097" ERROR: time zone displacement out of range: "Feb 16 17:32:01 -0097"
INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 16 17:32:01 5097 BC'); INSERT INTO TIMESTAMPTZ_TBL VALUES ('Feb 16 17:32:01 5097 BC');
ERROR: timestamp out of range: "Feb 16 17:32:01 5097 BC" ERROR: timestamp out of range: "Feb 16 17:32:01 5097 BC"
SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL; SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment