Reject combining "epoch" and "infinity" with other datetime fields.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 9 Mar 2023 21:49:03 +0000 (16:49 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 9 Mar 2023 21:49:03 +0000 (16:49 -0500)
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
src/test/regress/expected/horology.out
src/test/regress/sql/horology.sql

index 01660637a24d69db94ca750d66760748c319152c..a7558d39a0e41eec4b3c8dcbde2b70407c136072 100644 (file)
@@ -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)
index de736836904e65013fd541e8b709510a97be1225..4f01131077bf43556fe9e7dac833dea6e2accbf0 100644 (file)
@@ -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
 --
index 2724a2bbc7dd346afe986706f161251e3d800040..0676cac5d173e26523ef2edccf98998c03a70355 100644 (file)
@@ -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
 --