aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/datetime.c192
1 files changed, 93 insertions, 99 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index f8b82bac8a3..4440a3c477a 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.4 2008/01/02 22:05:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.160.2.5 2008/02/25 23:21:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,7 +37,10 @@ static int DecodeTime(char *str, int fmask, int *tmask,
static int DecodeTimezone(char *str, int *tzp);
static int DecodePosixTimezone(char *str, int *tzp);
static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
-static int DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm);
+static int DecodeDate(char *str, int fmask, int *tmask, int *is2digits,
+ struct pg_tm * tm);
+static int ValidateDate(int fmask, int is2digits, int bc,
+ struct pg_tm * tm);
static void TrimTrailingZeros(char *str);
@@ -1099,7 +1102,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
}
else
{
- dterr = DecodeDate(field[i], fmask, &tmask, tm);
+ dterr = DecodeDate(field[i], fmask,
+ &tmask, &is2digits, tm);
if (dterr)
return dterr;
}
@@ -1311,7 +1315,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
/* Embedded decimal and no date yet? */
if (cp != NULL && !(fmask & DTK_DATE_M))
{
- dterr = DecodeDate(field[i], fmask, &tmask, tm);
+ dterr = DecodeDate(field[i], fmask,
+ &tmask, &is2digits, tm);
if (dterr)
return dterr;
}
@@ -1536,51 +1541,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
if (tmask & fmask)
return DTERR_BAD_FORMAT;
fmask |= tmask;
- }
-
- if (fmask & DTK_M(YEAR))
- {
- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
- if (bc)
- {
- if (tm->tm_year > 0)
- tm->tm_year = -(tm->tm_year - 1);
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
- errmsg("inconsistent use of year %04d and \"BC\"",
- tm->tm_year)));
- }
- else if (is2digits)
- {
- if (tm->tm_year < 70)
- tm->tm_year += 2000;
- else if (tm->tm_year < 100)
- tm->tm_year += 1900;
- }
- }
-
- /* now that we have correct year, decode DOY */
- if (fmask & DTK_M(DOY))
- {
- j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
- &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
- }
-
- /* check for valid month */
- if (fmask & DTK_M(MONTH))
- {
- if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
- return DTERR_MD_FIELD_OVERFLOW;
- }
+ } /* end loop over fields */
- /* minimal check for valid day */
- if (fmask & DTK_M(DAY))
- {
- if (tm->tm_mday < 1 || tm->tm_mday > 31)
- return DTERR_MD_FIELD_OVERFLOW;
- }
+ /* do final checking/adjustment of Y/M/D fields */
+ dterr = ValidateDate(fmask, is2digits, bc, tm);
+ if (dterr)
+ return dterr;
+ /* handle AM/PM */
if (mer != HR24 && tm->tm_hour > 12)
return DTERR_FIELD_OVERFLOW;
if (mer == AM && tm->tm_hour == 12)
@@ -1598,14 +1566,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
return DTERR_BAD_FORMAT;
}
- /*
- * Check for valid day of month, now that we know for sure the 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])
- return DTERR_FIELD_OVERFLOW;
-
/* timezone not specified? then find local timezone if possible */
if (tzp != NULL && !(fmask & DTK_M(TZ)))
{
@@ -1775,6 +1735,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
int val;
int dterr;
int is2digits = FALSE;
+ int bc = FALSE;
int mer = HR24;
*dtype = DTK_TIME;
@@ -1805,7 +1766,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
if (i == 0 && nf >= 2 &&
(ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
{
- dterr = DecodeDate(field[i], fmask, &tmask, tm);
+ dterr = DecodeDate(field[i], fmask,
+ &tmask, &is2digits, tm);
if (dterr)
return dterr;
}
@@ -2076,7 +2038,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
*/
if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
{
- dterr = DecodeDate(field[i], fmask, &tmask, tm);
+ dterr = DecodeDate(field[i], fmask,
+ &tmask, &is2digits, tm);
if (dterr)
return dterr;
}
@@ -2205,6 +2168,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
mer = val;
break;
+ case ADBC:
+ bc = (val == BC);
+ break;
+
case UNITS:
tmask = 0;
ptype = val;
@@ -2240,8 +2207,14 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
if (tmask & fmask)
return DTERR_BAD_FORMAT;
fmask |= tmask;
- }
+ } /* end loop over fields */
+ /* do final checking/adjustment of Y/M/D fields */
+ dterr = ValidateDate(fmask, is2digits, bc, tm);
+ if (dterr)
+ return dterr;
+
+ /* handle AM/PM */
if (mer != HR24 && tm->tm_hour > 12)
return DTERR_FIELD_OVERFLOW;
if (mer == AM && tm->tm_hour == 12)
@@ -2300,10 +2273,15 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
* Decode date string which includes delimiters.
* Return 0 if okay, a DTERR code if not.
*
- * Insist on a complete set of fields.
+ * str: field to be parsed
+ * fmask: bitmask for field types already seen
+ * *tmask: receives bitmask for fields found here
+ * *is2digits: set to TRUE if we find 2-digit year
+ * *tm: field values are stored into appropriate members of this struct
*/
static int
-DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
+DecodeDate(char *str, int fmask, int *tmask, int *is2digits,
+ struct pg_tm * tm)
{
fsec_t fsec;
int nf = 0;
@@ -2311,13 +2289,13 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
len;
int dterr;
bool haveTextMonth = FALSE;
- int bc = FALSE;
- int is2digits = FALSE;
int type,
val,
dmask = 0;
char *field[MAXDATEFIELDS];
+ *tmask = 0;
+
/* parse this string... */
while (*str != '\0' && nf < MAXDATEFIELDS)
{
@@ -2343,14 +2321,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
nf++;
}
-#if 0
- /* don't allow too many fields */
- if (nf > 3)
- return DTERR_BAD_FORMAT;
-#endif
-
- *tmask = 0;
-
/* look first for text fields, since that will be unambiguous month */
for (i = 0; i < nf; i++)
{
@@ -2368,10 +2338,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
haveTextMonth = TRUE;
break;
- case ADBC:
- bc = (val == BC);
- break;
-
default:
return DTERR_BAD_FORMAT;
}
@@ -2397,7 +2363,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
&dmask, tm,
- &fsec, &is2digits);
+ &fsec, is2digits);
if (dterr)
return dterr;
@@ -2411,23 +2377,38 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
return DTERR_BAD_FORMAT;
- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
- if (bc)
- {
- if (tm->tm_year > 0)
- tm->tm_year = -(tm->tm_year - 1);
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
- errmsg("inconsistent use of year %04d and \"BC\"",
- tm->tm_year)));
- }
- else if (is2digits)
+ /* validation of the field values must wait until ValidateDate() */
+
+ return 0;
+}
+
+/* ValidateDate()
+ * Check valid year/month/day values, handle BC and DOY cases
+ * Return 0 if okay, a DTERR code if not.
+ */
+static int
+ValidateDate(int fmask, int is2digits, int bc, struct pg_tm * tm)
+{
+ if (fmask & DTK_M(YEAR))
{
- if (tm->tm_year < 70)
- tm->tm_year += 2000;
- else if (tm->tm_year < 100)
- tm->tm_year += 1900;
+ /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
+ if (bc)
+ {
+ if (tm->tm_year > 0)
+ tm->tm_year = -(tm->tm_year - 1);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
+ errmsg("inconsistent use of year %04d and \"BC\"",
+ tm->tm_year)));
+ }
+ else if (is2digits)
+ {
+ if (tm->tm_year < 70)
+ tm->tm_year += 2000;
+ else if (tm->tm_year < 100)
+ tm->tm_year += 1900;
+ }
}
/* now that we have correct year, decode DOY */
@@ -2438,16 +2419,29 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
}
/* check for valid month */
- if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
- return DTERR_MD_FIELD_OVERFLOW;
+ if (fmask & DTK_M(MONTH))
+ {
+ if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
+ return DTERR_MD_FIELD_OVERFLOW;
+ }
- /* check for valid day */
- if (tm->tm_mday < 1 || tm->tm_mday > 31)
- return DTERR_MD_FIELD_OVERFLOW;
+ /* minimal check for valid day */
+ if (fmask & DTK_M(DAY))
+ {
+ if (tm->tm_mday < 1 || tm->tm_mday > 31)
+ return DTERR_MD_FIELD_OVERFLOW;
+ }
- /* 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;
+ if ((fmask & DTK_DATE_M) == DTK_DATE_M)
+ {
+ /*
+ * Check for valid day of month, now that we know for sure the 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])
+ return DTERR_FIELD_OVERFLOW;
+ }
return 0;
}