@@ -69,7 +69,8 @@ static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp,
6969static bool DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,
7070 const char * abbr , pg_tz * tzp ,
7171 int * offset , int * isdst );
72- static pg_tz * FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl , const datetkn * tp );
72+ static pg_tz * FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl , const datetkn * tp ,
73+ DateTimeErrorExtra * extra );
7374
7475
7576const int day_tab [2 ][13 ] =
@@ -951,6 +952,9 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
951952 * Return 0 if full date, 1 if only time, and negative DTERR code if problems.
952953 * (Currently, all callers treat 1 as an error return too.)
953954 *
955+ * Inputs are field[] and ftype[] arrays, of length nf.
956+ * Other arguments are outputs.
957+ *
954958 * External format(s):
955959 * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
956960 * "Fri Feb-7-1997 15:23:27"
@@ -972,7 +976,8 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
972976 */
973977int
974978DecodeDateTime (char * * field , int * ftype , int nf ,
975- int * dtype , struct pg_tm * tm , fsec_t * fsec , int * tzp )
979+ int * dtype , struct pg_tm * tm , fsec_t * fsec , int * tzp ,
980+ DateTimeErrorExtra * extra )
976981{
977982 int fmask = 0 ,
978983 tmask ,
@@ -1112,15 +1117,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
11121117 namedTz = pg_tzset (field [i ]);
11131118 if (!namedTz )
11141119 {
1115- /*
1116- * We should return an error code instead of
1117- * ereport'ing directly, but then there is no way
1118- * to report the bad time zone name.
1119- */
1120- ereport (ERROR ,
1121- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1122- errmsg ("time zone \"%s\" not recognized" ,
1123- field [i ])));
1120+ extra -> dtee_timezone = field [i ];
1121+ return DTERR_BAD_TIMEZONE ;
11241122 }
11251123 /* we'll apply the zone setting below */
11261124 tmask = DTK_M (TZ );
@@ -1376,7 +1374,10 @@ DecodeDateTime(char **field, int *ftype, int nf,
13761374 case DTK_STRING :
13771375 case DTK_SPECIAL :
13781376 /* timezone abbrevs take precedence over built-in tokens */
1379- type = DecodeTimezoneAbbrev (i , field [i ], & val , & valtz );
1377+ dterr = DecodeTimezoneAbbrev (i , field [i ],
1378+ & type , & val , & valtz , extra );
1379+ if (dterr )
1380+ return dterr ;
13801381 if (type == UNKNOWN_FIELD )
13811382 type = DecodeSpecial (i , field [i ], & val );
13821383 if (type == IGNORE_DTF )
@@ -1912,6 +1913,9 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
19121913 * Interpret parsed string as time fields only.
19131914 * Returns 0 if successful, DTERR code if bogus input detected.
19141915 *
1916+ * Inputs are field[] and ftype[] arrays, of length nf.
1917+ * Other arguments are outputs.
1918+ *
19151919 * Note that support for time zone is here for
19161920 * SQL TIME WITH TIME ZONE, but it reveals
19171921 * bogosity with SQL date/time standards, since
@@ -1922,7 +1926,8 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
19221926 */
19231927int
19241928DecodeTimeOnly (char * * field , int * ftype , int nf ,
1925- int * dtype , struct pg_tm * tm , fsec_t * fsec , int * tzp )
1929+ int * dtype , struct pg_tm * tm , fsec_t * fsec , int * tzp ,
1930+ DateTimeErrorExtra * extra )
19261931{
19271932 int fmask = 0 ,
19281933 tmask ,
@@ -2018,15 +2023,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
20182023 namedTz = pg_tzset (field [i ]);
20192024 if (!namedTz )
20202025 {
2021- /*
2022- * We should return an error code instead of
2023- * ereport'ing directly, but then there is no way
2024- * to report the bad time zone name.
2025- */
2026- ereport (ERROR ,
2027- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
2028- errmsg ("time zone \"%s\" not recognized" ,
2029- field [i ])));
2026+ extra -> dtee_timezone = field [i ];
2027+ return DTERR_BAD_TIMEZONE ;
20302028 }
20312029 /* we'll apply the zone setting below */
20322030 ftype [i ] = DTK_TZ ;
@@ -2278,7 +2276,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
22782276 case DTK_STRING :
22792277 case DTK_SPECIAL :
22802278 /* timezone abbrevs take precedence over built-in tokens */
2281- type = DecodeTimezoneAbbrev (i , field [i ], & val , & valtz );
2279+ dterr = DecodeTimezoneAbbrev (i , field [i ],
2280+ & type , & val , & valtz , extra );
2281+ if (dterr )
2282+ return dterr ;
22822283 if (type == UNKNOWN_FIELD )
22832284 type = DecodeSpecial (i , field [i ], & val );
22842285 if (type == IGNORE_DTF )
@@ -3211,22 +3212,28 @@ DecodeTimezone(const char *str, int *tzp)
32113212/* DecodeTimezoneAbbrev()
32123213 * Interpret string as a timezone abbreviation, if possible.
32133214 *
3214- * Returns an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
3215+ * Sets *ftype to an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
32153216 * string is not any known abbreviation. On success, set *offset and *tz to
32163217 * represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
32173218 * Note that full timezone names (such as America/New_York) are not handled
32183219 * here, mostly for historical reasons.
32193220 *
3221+ * The function result is 0 or a DTERR code; in the latter case, *extra
3222+ * is filled as needed. Note that unknown-abbreviation is not considered
3223+ * an error case. Also note that many callers assume that the DTERR code
3224+ * is one that DateTimeParseError does not require "str" or "datatype"
3225+ * strings for.
3226+ *
32203227 * Given string must be lowercased already.
32213228 *
32223229 * Implement a cache lookup since it is likely that dates
32233230 * will be related in format.
32243231 */
32253232int
32263233DecodeTimezoneAbbrev (int field , const char * lowtoken ,
3227- int * offset , pg_tz * * tz )
3234+ int * ftype , int * offset , pg_tz * * tz ,
3235+ DateTimeErrorExtra * extra )
32283236{
3229- int type ;
32303237 const datetkn * tp ;
32313238
32323239 tp = abbrevcache [field ];
@@ -3241,18 +3248,20 @@ DecodeTimezoneAbbrev(int field, const char *lowtoken,
32413248 }
32423249 if (tp == NULL )
32433250 {
3244- type = UNKNOWN_FIELD ;
3251+ * ftype = UNKNOWN_FIELD ;
32453252 * offset = 0 ;
32463253 * tz = NULL ;
32473254 }
32483255 else
32493256 {
32503257 abbrevcache [field ] = tp ;
3251- type = tp -> type ;
3252- if (type == DYNTZ )
3258+ * ftype = tp -> type ;
3259+ if (tp -> type == DYNTZ )
32533260 {
32543261 * offset = 0 ;
3255- * tz = FetchDynamicTimeZone (zoneabbrevtbl , tp );
3262+ * tz = FetchDynamicTimeZone (zoneabbrevtbl , tp , extra );
3263+ if (* tz == NULL )
3264+ return DTERR_BAD_ZONE_ABBREV ;
32563265 }
32573266 else
32583267 {
@@ -3261,7 +3270,7 @@ DecodeTimezoneAbbrev(int field, const char *lowtoken,
32613270 }
32623271 }
32633272
3264- return type ;
3273+ return 0 ;
32653274}
32663275
32673276
@@ -4014,15 +4023,21 @@ DecodeUnits(int field, const char *lowtoken, int *val)
40144023/*
40154024 * Report an error detected by one of the datetime input processing routines.
40164025 *
4017- * dterr is the error code, str is the original input string, datatype is
4018- * the name of the datatype we were trying to accept.
4026+ * dterr is the error code, and *extra contains any auxiliary info we need
4027+ * for the error report. extra can be NULL if not needed for the particular
4028+ * dterr value.
4029+ *
4030+ * str is the original input string, and datatype is the name of the datatype
4031+ * we were trying to accept. (For some DTERR codes, these are not used and
4032+ * can be NULL.)
40194033 *
40204034 * Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
40214035 * DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
40224036 * separate SQLSTATE codes, so ...
40234037 */
40244038void
4025- DateTimeParseError (int dterr , const char * str , const char * datatype )
4039+ DateTimeParseError (int dterr , DateTimeErrorExtra * extra ,
4040+ const char * str , const char * datatype )
40264041{
40274042 switch (dterr )
40284043 {
@@ -4052,6 +4067,20 @@ DateTimeParseError(int dterr, const char *str, const char *datatype)
40524067 errmsg ("time zone displacement out of range: \"%s\"" ,
40534068 str )));
40544069 break ;
4070+ case DTERR_BAD_TIMEZONE :
4071+ ereport (ERROR ,
4072+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
4073+ errmsg ("time zone \"%s\" not recognized" ,
4074+ extra -> dtee_timezone )));
4075+ break ;
4076+ case DTERR_BAD_ZONE_ABBREV :
4077+ ereport (ERROR ,
4078+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
4079+ errmsg ("time zone \"%s\" not recognized" ,
4080+ extra -> dtee_timezone ),
4081+ errdetail ("This time zone name appears in the configuration file for time zone abbreviation \"%s\"." ,
4082+ extra -> dtee_abbrev )));
4083+ break ;
40554084 case DTERR_BAD_FORMAT :
40564085 default :
40574086 ereport (ERROR ,
@@ -4880,9 +4909,12 @@ InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
48804909
48814910/*
48824911 * Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
4912+ *
4913+ * On failure, returns NULL and fills *extra for a DTERR_BAD_ZONE_ABBREV error.
48834914 */
48844915static pg_tz *
4885- FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl , const datetkn * tp )
4916+ FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl , const datetkn * tp ,
4917+ DateTimeErrorExtra * extra )
48864918{
48874919 DynamicZoneAbbrev * dtza ;
48884920
@@ -4896,18 +4928,12 @@ FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
48964928 if (dtza -> tz == NULL )
48974929 {
48984930 dtza -> tz = pg_tzset (dtza -> zone );
4899-
4900- /*
4901- * Ideally we'd let the caller ereport instead of doing it here, but
4902- * then there is no way to report the bad time zone name.
4903- */
49044931 if (dtza -> tz == NULL )
4905- ereport (ERROR ,
4906- (errcode (ERRCODE_CONFIG_FILE_ERROR ),
4907- errmsg ("time zone \"%s\" not recognized" ,
4908- dtza -> zone ),
4909- errdetail ("This time zone name appears in the configuration file for time zone abbreviation \"%s\"." ,
4910- tp -> token )));
4932+ {
4933+ /* Ooops, bogus zone name in config file entry */
4934+ extra -> dtee_timezone = dtza -> zone ;
4935+ extra -> dtee_abbrev = tp -> token ;
4936+ }
49114937 }
49124938 return dtza -> tz ;
49134939}
@@ -4993,10 +5019,14 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
49935019 {
49945020 /* Determine the current meaning of the abbrev */
49955021 pg_tz * tzp ;
5022+ DateTimeErrorExtra extra ;
49965023 TimestampTz now ;
49975024 int isdst ;
49985025
4999- tzp = FetchDynamicTimeZone (zoneabbrevtbl , tp );
5026+ tzp = FetchDynamicTimeZone (zoneabbrevtbl , tp , & extra );
5027+ if (tzp == NULL )
5028+ DateTimeParseError (DTERR_BAD_ZONE_ABBREV , & extra ,
5029+ NULL , NULL );
50005030 now = GetCurrentTransactionStartTimestamp ();
50015031 gmtoffset = - DetermineTimeZoneAbbrevOffsetTS (now ,
50025032 tp -> token ,
0 commit comments