diff options
author | Michael Paquier <michael@paquier.xyz> | 2023-08-28 14:27:17 +0900 |
---|---|---|
committer | Michael Paquier <michael@paquier.xyz> | 2023-08-28 14:27:17 +0900 |
commit | 617f9b7d4b10fec00a86802eeb34d7295c52d747 (patch) | |
tree | 8b2fd69b379df49ec705940c4d1a41cc7299e727 | |
parent | 165d581f146b09543b832513ee00fead132ba6b1 (diff) | |
download | postgresql-617f9b7d4b10fec00a86802eeb34d7295c52d747.tar.gz postgresql-617f9b7d4b10fec00a86802eeb34d7295c52d747.zip |
Tighten unit parsing in internal values
Interval values now generate an error when the user has multiple
consecutive units or a unit without a value. Previously, it was
possible to specify multiple units consecutively which is contrary to
what the documentation allows, so it was possible to finish with
confusing interval values.
This is a follow-up of the work done in 165d581f146b.
Author: Joseph Koshakow
Reviewed-by: Jacob Champion, Gurjeet Singh, Reid Thompson
Discussion: https://postgr.es/m/CAAvxfHd-yNO+XYnUxL=GaNZ1n+eE0V-oE0+-cC1jdjdU0KS3iw@mail.gmail.com
-rw-r--r-- | src/backend/utils/adt/datetime.c | 12 | ||||
-rw-r--r-- | src/test/regress/expected/interval.out | 9 | ||||
-rw-r--r-- | src/test/regress/sql/interval.sql | 4 |
3 files changed, 25 insertions, 0 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 178b3f47803..267dfd37b2e 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -3278,6 +3278,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, { bool force_negative = false; bool is_before = false; + bool parsing_unit_val = false; char *cp; int fmask = 0, tmask, @@ -3336,6 +3337,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, itm_in->tm_usec > 0) itm_in->tm_usec = -itm_in->tm_usec; type = DTK_DAY; + parsing_unit_val = false; break; case DTK_TZ: @@ -3373,6 +3375,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, * are reading right to left. */ type = DTK_DAY; + parsing_unit_val = false; break; } @@ -3562,10 +3565,14 @@ DecodeInterval(char **field, int *ftype, int nf, int range, default: return DTERR_BAD_FORMAT; } + parsing_unit_val = false; break; case DTK_STRING: case DTK_SPECIAL: + /* reject consecutive unhandled units */ + if (parsing_unit_val) + return DTERR_BAD_FORMAT; type = DecodeUnits(i, field[i], &uval); if (type == IGNORE_DTF) continue; @@ -3575,6 +3582,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, { case UNITS: type = uval; + parsing_unit_val = true; break; case AGO: @@ -3607,6 +3615,10 @@ DecodeInterval(char **field, int *ftype, int nf, int range, if (fmask == 0) return DTERR_BAD_FORMAT; + /* reject if unit appeared and was never handled */ + if (parsing_unit_val) + return DTERR_BAD_FORMAT; + /* finally, AGO negates everything */ if (is_before) { diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index 01d43b58687..c0ca8e041b1 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -1796,3 +1796,12 @@ SELECT INTERVAL '2 minutes ago 5 days'; ERROR: invalid input syntax for type interval: "2 minutes ago 5 days" LINE 1: SELECT INTERVAL '2 minutes ago 5 days'; ^ +-- consecutive and dangling units are not allowed. +SELECT INTERVAL 'hour 5 months'; +ERROR: invalid input syntax for type interval: "hour 5 months" +LINE 1: SELECT INTERVAL 'hour 5 months'; + ^ +SELECT INTERVAL '1 year months days 5 hours'; +ERROR: invalid input syntax for type interval: "1 year months days 5 hours" +LINE 1: SELECT INTERVAL '1 year months days 5 hours'; + ^ diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index fb1ef304904..038fc508d0c 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -586,3 +586,7 @@ SELECT extract(epoch from interval '1000000000 days'); -- "ago" can only appear once at the end of an interval. SELECT INTERVAL '42 days 2 seconds ago ago'; SELECT INTERVAL '2 minutes ago 5 days'; + +-- consecutive and dangling units are not allowed. +SELECT INTERVAL 'hour 5 months'; +SELECT INTERVAL '1 year months days 5 hours'; |