Re-allow input of Julian dates prior to 0001-01-01 AD.

This was unintentionally broken in 8.4 while tightening up checking of
ordinary non-Julian date inputs to forbid references to "year zero".
Per bug #5672 from Benjamin Gigot.
This commit is contained in:
Tom Lane 2010-09-22 23:48:07 -04:00
parent 804b27613b
commit 9aae81527f
3 changed files with 41 additions and 12 deletions

View File

@ -42,7 +42,7 @@ static int DecodeTimezone(char *str, int *tzp);
static const datetkn *datebsearch(const char *key, const datetkn *base, int nel); static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
struct pg_tm * tm); struct pg_tm * tm);
static int ValidateDate(int fmask, bool is2digits, bool bc, static int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
struct pg_tm * tm); struct pg_tm * tm);
static void TrimTrailingZeros(char *str); static void TrimTrailingZeros(char *str);
static void AppendSeconds(char *cp, int sec, fsec_t fsec, static void AppendSeconds(char *cp, int sec, fsec_t fsec,
@ -795,6 +795,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
int dterr; int dterr;
int mer = HR24; int mer = HR24;
bool haveTextMonth = FALSE; bool haveTextMonth = FALSE;
bool isjulian = FALSE;
bool is2digits = FALSE; bool is2digits = FALSE;
bool bc = FALSE; bool bc = FALSE;
pg_tz *namedTz = NULL; pg_tz *namedTz = NULL;
@ -833,10 +834,12 @@ DecodeDateTime(char **field, int *ftype, int nf,
errno = 0; errno = 0;
val = strtoi(field[i], &cp, 10); val = strtoi(field[i], &cp, 10);
if (errno == ERANGE) if (errno == ERANGE || val < 0)
return DTERR_FIELD_OVERFLOW; return DTERR_FIELD_OVERFLOW;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
isjulian = TRUE;
/* Get the time zone from the end of the string */ /* Get the time zone from the end of the string */
dterr = DecodeTimezone(cp, tzp); dterr = DecodeTimezone(cp, tzp);
if (dterr) if (dterr)
@ -1065,11 +1068,13 @@ DecodeDateTime(char **field, int *ftype, int nf,
break; break;
case DTK_JULIAN: case DTK_JULIAN:
/*** /* previous field was a label for "julian date" */
* previous field was a label for "julian date"? if (val < 0)
***/ return DTERR_FIELD_OVERFLOW;
tmask = DTK_DATE_M; tmask = DTK_DATE_M;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
isjulian = TRUE;
/* fractional Julian Day? */ /* fractional Julian Day? */
if (*cp == '.') if (*cp == '.')
{ {
@ -1361,7 +1366,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
} /* end loop over fields */ } /* end loop over fields */
/* do final checking/adjustment of Y/M/D fields */ /* do final checking/adjustment of Y/M/D fields */
dterr = ValidateDate(fmask, is2digits, bc, tm); dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
if (dterr) if (dterr)
return dterr; return dterr;
@ -1564,6 +1569,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
int i; int i;
int val; int val;
int dterr; int dterr;
bool isjulian = FALSE;
bool is2digits = FALSE; bool is2digits = FALSE;
bool bc = FALSE; bool bc = FALSE;
int mer = HR24; int mer = HR24;
@ -1795,11 +1801,13 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
break; break;
case DTK_JULIAN: case DTK_JULIAN:
/*** /* previous field was a label for "julian date" */
* previous field was a label for "julian date"? if (val < 0)
***/ return DTERR_FIELD_OVERFLOW;
tmask = DTK_DATE_M; tmask = DTK_DATE_M;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
isjulian = TRUE;
if (*cp == '.') if (*cp == '.')
{ {
double time; double time;
@ -2045,7 +2053,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
} /* end loop over fields */ } /* end loop over fields */
/* do final checking/adjustment of Y/M/D fields */ /* do final checking/adjustment of Y/M/D fields */
dterr = ValidateDate(fmask, is2digits, bc, tm); dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
if (dterr) if (dterr)
return dterr; return dterr;
@ -2247,11 +2255,16 @@ DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
* Return 0 if okay, a DTERR code if not. * Return 0 if okay, a DTERR code if not.
*/ */
static int static int
ValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm) ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
struct pg_tm * tm)
{ {
if (fmask & DTK_M(YEAR)) if (fmask & DTK_M(YEAR))
{ {
if (bc) if (isjulian)
{
/* tm_year is correct and should not be touched */
}
else if (bc)
{ {
/* there is no year zero in AD/BC notation */ /* there is no year zero in AD/BC notation */
if (tm->tm_year <= 0) if (tm->tm_year <= 0)

View File

@ -264,6 +264,19 @@ SELECT time with time zone 'T040506.789 -08';
(1 row) (1 row)
SET DateStyle = 'Postgres, MDY'; SET DateStyle = 'Postgres, MDY';
-- Check Julian dates BC
SELECT date 'J1520447' AS "Confucius' Birthday";
Confucius' Birthday
---------------------
09-28-0551 BC
(1 row)
SELECT date 'J0' AS "Julian Epoch";
Julian Epoch
---------------
11-24-4714 BC
(1 row)
-- --
-- date, time arithmetic -- date, time arithmetic
-- --

View File

@ -56,6 +56,9 @@ SELECT time with time zone 'T040506.789-08';
SELECT time with time zone 'T040506.789 +08'; SELECT time with time zone 'T040506.789 +08';
SELECT time with time zone 'T040506.789 -08'; SELECT time with time zone 'T040506.789 -08';
SET DateStyle = 'Postgres, MDY'; SET DateStyle = 'Postgres, MDY';
-- Check Julian dates BC
SELECT date 'J1520447' AS "Confucius' Birthday";
SELECT date 'J0' AS "Julian Epoch";
-- --
-- date, time arithmetic -- date, time arithmetic