aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-09-22 23:48:20 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2010-09-22 23:48:20 -0400
commitfcb2326180ebad04106f745f646c4e02bc9ff10f (patch)
tree7b3c3fb35dabc0ab576fce8af560c3b022c6d548
parent41b04faf7d5aacbf613fc5ab6cf85899b99ef9f8 (diff)
downloadpostgresql-fcb2326180ebad04106f745f646c4e02bc9ff10f.tar.gz
postgresql-fcb2326180ebad04106f745f646c4e02bc9ff10f.zip
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.
-rw-r--r--src/backend/utils/adt/datetime.c37
-rw-r--r--src/test/regress/expected/horology.out13
-rw-r--r--src/test/regress/sql/horology.sql3
3 files changed, 41 insertions, 12 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 8a3ab236056..21c689cd191 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -42,7 +42,7 @@ static int DecodeTimezone(char *str, int *tzp);
static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
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);
static void TrimTrailingZeros(char *str);
static void AppendSeconds(char *cp, int sec, fsec_t fsec,
@@ -795,6 +795,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
int dterr;
int mer = HR24;
bool haveTextMonth = FALSE;
+ bool isjulian = FALSE;
bool is2digits = FALSE;
bool bc = FALSE;
pg_tz *namedTz = NULL;
@@ -833,10 +834,12 @@ DecodeDateTime(char **field, int *ftype, int nf,
errno = 0;
val = strtoi(field[i], &cp, 10);
- if (errno == ERANGE)
+ if (errno == ERANGE || val < 0)
return DTERR_FIELD_OVERFLOW;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ isjulian = TRUE;
+
/* Get the time zone from the end of the string */
dterr = DecodeTimezone(cp, tzp);
if (dterr)
@@ -1065,11 +1068,13 @@ DecodeDateTime(char **field, int *ftype, int nf,
break;
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;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ isjulian = TRUE;
+
/* fractional Julian Day? */
if (*cp == '.')
{
@@ -1361,7 +1366,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
} /* end loop over 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)
return dterr;
@@ -1564,6 +1569,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
int i;
int val;
int dterr;
+ bool isjulian = FALSE;
bool is2digits = FALSE;
bool bc = FALSE;
int mer = HR24;
@@ -1795,11 +1801,13 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
break;
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;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ isjulian = TRUE;
+
if (*cp == '.')
{
double time;
@@ -2045,7 +2053,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
} /* end loop over 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)
return dterr;
@@ -2247,11 +2255,16 @@ DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
* Return 0 if okay, a DTERR code if not.
*/
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 (bc)
+ if (isjulian)
+ {
+ /* tm_year is correct and should not be touched */
+ }
+ else if (bc)
{
/* there is no year zero in AD/BC notation */
if (tm->tm_year <= 0)
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 26d7541b720..b13f7d7c5b5 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -264,6 +264,19 @@ SELECT time with time zone 'T040506.789 -08';
(1 row)
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
--
diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql
index 615755e3de0..97ff9f20c79 100644
--- a/src/test/regress/sql/horology.sql
+++ b/src/test/regress/sql/horology.sql
@@ -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';
SET DateStyle = 'Postgres, MDY';
+-- Check Julian dates BC
+SELECT date 'J1520447' AS "Confucius' Birthday";
+SELECT date 'J0' AS "Julian Epoch";
--
-- date, time arithmetic