Skip to content

Commit 9aae815

Browse files
committed
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.
1 parent 804b276 commit 9aae815

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

src/backend/utils/adt/datetime.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static int DecodeTimezone(char *str, int *tzp);
4242
static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
4343
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
4444
struct pg_tm * tm);
45-
static int ValidateDate(int fmask, bool is2digits, bool bc,
45+
static int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
4646
struct pg_tm * tm);
4747
static void TrimTrailingZeros(char *str);
4848
static void AppendSeconds(char *cp, int sec, fsec_t fsec,
@@ -795,6 +795,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
795795
int dterr;
796796
int mer = HR24;
797797
bool haveTextMonth = FALSE;
798+
bool isjulian = FALSE;
798799
bool is2digits = FALSE;
799800
bool bc = FALSE;
800801
pg_tz *namedTz = NULL;
@@ -833,10 +834,12 @@ DecodeDateTime(char **field, int *ftype, int nf,
833834

834835
errno = 0;
835836
val = strtoi(field[i], &cp, 10);
836-
if (errno == ERANGE)
837+
if (errno == ERANGE || val < 0)
837838
return DTERR_FIELD_OVERFLOW;
838839

839840
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
841+
isjulian = TRUE;
842+
840843
/* Get the time zone from the end of the string */
841844
dterr = DecodeTimezone(cp, tzp);
842845
if (dterr)
@@ -1065,11 +1068,13 @@ DecodeDateTime(char **field, int *ftype, int nf,
10651068
break;
10661069

10671070
case DTK_JULIAN:
1068-
/***
1069-
* previous field was a label for "julian date"?
1070-
***/
1071+
/* previous field was a label for "julian date" */
1072+
if (val < 0)
1073+
return DTERR_FIELD_OVERFLOW;
10711074
tmask = DTK_DATE_M;
10721075
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1076+
isjulian = TRUE;
1077+
10731078
/* fractional Julian Day? */
10741079
if (*cp == '.')
10751080
{
@@ -1361,7 +1366,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
13611366
} /* end loop over fields */
13621367

13631368
/* do final checking/adjustment of Y/M/D fields */
1364-
dterr = ValidateDate(fmask, is2digits, bc, tm);
1369+
dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
13651370
if (dterr)
13661371
return dterr;
13671372

@@ -1564,6 +1569,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
15641569
int i;
15651570
int val;
15661571
int dterr;
1572+
bool isjulian = FALSE;
15671573
bool is2digits = FALSE;
15681574
bool bc = FALSE;
15691575
int mer = HR24;
@@ -1795,11 +1801,13 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
17951801
break;
17961802

17971803
case DTK_JULIAN:
1798-
/***
1799-
* previous field was a label for "julian date"?
1800-
***/
1804+
/* previous field was a label for "julian date" */
1805+
if (val < 0)
1806+
return DTERR_FIELD_OVERFLOW;
18011807
tmask = DTK_DATE_M;
18021808
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1809+
isjulian = TRUE;
1810+
18031811
if (*cp == '.')
18041812
{
18051813
double time;
@@ -2045,7 +2053,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
20452053
} /* end loop over fields */
20462054

20472055
/* do final checking/adjustment of Y/M/D fields */
2048-
dterr = ValidateDate(fmask, is2digits, bc, tm);
2056+
dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
20492057
if (dterr)
20502058
return dterr;
20512059

@@ -2247,11 +2255,16 @@ DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
22472255
* Return 0 if okay, a DTERR code if not.
22482256
*/
22492257
static int
2250-
ValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm)
2258+
ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
2259+
struct pg_tm * tm)
22512260
{
22522261
if (fmask & DTK_M(YEAR))
22532262
{
2254-
if (bc)
2263+
if (isjulian)
2264+
{
2265+
/* tm_year is correct and should not be touched */
2266+
}
2267+
else if (bc)
22552268
{
22562269
/* there is no year zero in AD/BC notation */
22572270
if (tm->tm_year <= 0)

src/test/regress/expected/horology.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,19 @@ SELECT time with time zone 'T040506.789 -08';
264264
(1 row)
265265

266266
SET DateStyle = 'Postgres, MDY';
267+
-- Check Julian dates BC
268+
SELECT date 'J1520447' AS "Confucius' Birthday";
269+
Confucius' Birthday
270+
---------------------
271+
09-28-0551 BC
272+
(1 row)
273+
274+
SELECT date 'J0' AS "Julian Epoch";
275+
Julian Epoch
276+
---------------
277+
11-24-4714 BC
278+
(1 row)
279+
267280
--
268281
-- date, time arithmetic
269282
--

src/test/regress/sql/horology.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ SELECT time with time zone 'T040506.789-08';
5656
SELECT time with time zone 'T040506.789 +08';
5757
SELECT time with time zone 'T040506.789 -08';
5858
SET DateStyle = 'Postgres, MDY';
59+
-- Check Julian dates BC
60+
SELECT date 'J1520447' AS "Confucius' Birthday";
61+
SELECT date 'J0' AS "Julian Epoch";
5962

6063
--
6164
-- date, time arithmetic

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy