From bcc704b52490492e6bd73c4444056b3e9644504d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 9 Mar 2023 16:49:03 -0500 Subject: [PATCH] Reject combining "epoch" and "infinity" with other datetime fields. Datetime input formerly accepted combinations such as '1995-08-06 infinity', but this seems like a clear error. Reject any combination of regular y/m/d/h/m/s fields with these special tokens. Joseph Koshakow, reviewed by Keisuke Kuroda and myself Discussion: https://postgr.es/m/CAAvxfHdm8wwXwG_FFRaJ1nTHiMWb7YXS2YKCzCt8Q0a2ZoMcHg@mail.gmail.com --- src/backend/utils/adt/datetime.c | 40 +++++++----- src/test/regress/expected/horology.out | 85 ++++++++++++++++++++++++++ src/test/regress/sql/horology.sql | 23 +++++++ 3 files changed, 133 insertions(+), 15 deletions(-) diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 01660637a2..a7558d39a0 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -1431,8 +1431,17 @@ DecodeDateTime(char **field, int *ftype, int nf, *tzp = 0; break; - default: + case DTK_EPOCH: + case DTK_LATE: + case DTK_EARLY: + tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ)); *dtype = val; + /* caller ignores tm for these dtype codes */ + break; + + default: + elog(ERROR, "unrecognized RESERV datetime token: %d", + val); } break; @@ -1567,22 +1576,23 @@ DecodeDateTime(char **field, int *ftype, int nf, fmask |= tmask; } /* end loop over fields */ - /* do final checking/adjustment of Y/M/D fields */ - dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm); - if (dterr) - return dterr; - - /* handle AM/PM */ - if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2) - return DTERR_FIELD_OVERFLOW; - if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2) - tm->tm_hour = 0; - else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2) - tm->tm_hour += HOURS_PER_DAY / 2; - - /* do additional checking for full date specs... */ + /* do additional checking for normal date specs (but not "infinity" etc) */ if (*dtype == DTK_DATE) { + /* do final checking/adjustment of Y/M/D fields */ + dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm); + if (dterr) + return dterr; + + /* handle AM/PM */ + if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2) + return DTERR_FIELD_OVERFLOW; + if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2) + tm->tm_hour = 0; + else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2) + tm->tm_hour += HOURS_PER_DAY / 2; + + /* check for incomplete input */ if ((fmask & DTK_DATE_M) != DTK_DATE_M) { if ((fmask & DTK_TIME_M) == DTK_TIME_M) diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index de73683690..4f01131077 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -283,6 +283,91 @@ SELECT date 'J0' AS "Julian Epoch"; 11-24-4714 BC (1 row) +-- conflicting fields should throw errors +SELECT date '1995-08-06 epoch'; +ERROR: invalid input syntax for type date: "1995-08-06 epoch" +LINE 1: SELECT date '1995-08-06 epoch'; + ^ +SELECT date '1995-08-06 infinity'; +ERROR: invalid input syntax for type date: "1995-08-06 infinity" +LINE 1: SELECT date '1995-08-06 infinity'; + ^ +SELECT date '1995-08-06 -infinity'; +ERROR: invalid input syntax for type date: "1995-08-06 -infinity" +LINE 1: SELECT date '1995-08-06 -infinity'; + ^ +SELECT date 'today infinity'; +ERROR: invalid input syntax for type date: "today infinity" +LINE 1: SELECT date 'today infinity'; + ^ +SELECT date '-infinity infinity'; +ERROR: invalid input syntax for type date: "-infinity infinity" +LINE 1: SELECT date '-infinity infinity'; + ^ +SELECT timestamp '1995-08-06 epoch'; +ERROR: invalid input syntax for type timestamp: "1995-08-06 epoch" +LINE 1: SELECT timestamp '1995-08-06 epoch'; + ^ +SELECT timestamp '1995-08-06 infinity'; +ERROR: invalid input syntax for type timestamp: "1995-08-06 infinity" +LINE 1: SELECT timestamp '1995-08-06 infinity'; + ^ +SELECT timestamp '1995-08-06 -infinity'; +ERROR: invalid input syntax for type timestamp: "1995-08-06 -infinity" +LINE 1: SELECT timestamp '1995-08-06 -infinity'; + ^ +SELECT timestamp 'epoch 01:01:01'; +ERROR: invalid input syntax for type timestamp: "epoch 01:01:01" +LINE 1: SELECT timestamp 'epoch 01:01:01'; + ^ +SELECT timestamp 'infinity 01:01:01'; +ERROR: invalid input syntax for type timestamp: "infinity 01:01:01" +LINE 1: SELECT timestamp 'infinity 01:01:01'; + ^ +SELECT timestamp '-infinity 01:01:01'; +ERROR: invalid input syntax for type timestamp: "-infinity 01:01:01" +LINE 1: SELECT timestamp '-infinity 01:01:01'; + ^ +SELECT timestamp 'now epoch'; +ERROR: invalid input syntax for type timestamp: "now epoch" +LINE 1: SELECT timestamp 'now epoch'; + ^ +SELECT timestamp '-infinity infinity'; +ERROR: invalid input syntax for type timestamp: "-infinity infinity" +LINE 1: SELECT timestamp '-infinity infinity'; + ^ +SELECT timestamptz '1995-08-06 epoch'; +ERROR: invalid input syntax for type timestamp with time zone: "1995-08-06 epoch" +LINE 1: SELECT timestamptz '1995-08-06 epoch'; + ^ +SELECT timestamptz '1995-08-06 infinity'; +ERROR: invalid input syntax for type timestamp with time zone: "1995-08-06 infinity" +LINE 1: SELECT timestamptz '1995-08-06 infinity'; + ^ +SELECT timestamptz '1995-08-06 -infinity'; +ERROR: invalid input syntax for type timestamp with time zone: "1995-08-06 -infinity" +LINE 1: SELECT timestamptz '1995-08-06 -infinity'; + ^ +SELECT timestamptz 'epoch 01:01:01'; +ERROR: invalid input syntax for type timestamp with time zone: "epoch 01:01:01" +LINE 1: SELECT timestamptz 'epoch 01:01:01'; + ^ +SELECT timestamptz 'infinity 01:01:01'; +ERROR: invalid input syntax for type timestamp with time zone: "infinity 01:01:01" +LINE 1: SELECT timestamptz 'infinity 01:01:01'; + ^ +SELECT timestamptz '-infinity 01:01:01'; +ERROR: invalid input syntax for type timestamp with time zone: "-infinity 01:01:01" +LINE 1: SELECT timestamptz '-infinity 01:01:01'; + ^ +SELECT timestamptz 'now epoch'; +ERROR: invalid input syntax for type timestamp with time zone: "now epoch" +LINE 1: SELECT timestamptz 'now epoch'; + ^ +SELECT timestamptz '-infinity infinity'; +ERROR: invalid input syntax for type timestamp with time zone: "-infinity infinity" +LINE 1: SELECT timestamptz '-infinity infinity'; + ^ -- -- date, time arithmetic -- diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql index 2724a2bbc7..0676cac5d1 100644 --- a/src/test/regress/sql/horology.sql +++ b/src/test/regress/sql/horology.sql @@ -62,6 +62,29 @@ SET DateStyle = 'Postgres, MDY'; SELECT date 'J1520447' AS "Confucius' Birthday"; SELECT date 'J0' AS "Julian Epoch"; +-- conflicting fields should throw errors +SELECT date '1995-08-06 epoch'; +SELECT date '1995-08-06 infinity'; +SELECT date '1995-08-06 -infinity'; +SELECT date 'today infinity'; +SELECT date '-infinity infinity'; +SELECT timestamp '1995-08-06 epoch'; +SELECT timestamp '1995-08-06 infinity'; +SELECT timestamp '1995-08-06 -infinity'; +SELECT timestamp 'epoch 01:01:01'; +SELECT timestamp 'infinity 01:01:01'; +SELECT timestamp '-infinity 01:01:01'; +SELECT timestamp 'now epoch'; +SELECT timestamp '-infinity infinity'; +SELECT timestamptz '1995-08-06 epoch'; +SELECT timestamptz '1995-08-06 infinity'; +SELECT timestamptz '1995-08-06 -infinity'; +SELECT timestamptz 'epoch 01:01:01'; +SELECT timestamptz 'infinity 01:01:01'; +SELECT timestamptz '-infinity 01:01:01'; +SELECT timestamptz 'now epoch'; +SELECT timestamptz '-infinity infinity'; + -- -- date, time arithmetic --