Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2661469

Browse files
committed
Allow DateTimeParseError to handle bad-timezone error messages.
Pay down some ancient technical debt (dating to commit022fd99):fix a couple of places in datetime parsing that were throwingereport's immediately instead of returning a DTERR code that could beinterpreted by DateTimeParseError. The reason for that was that therewas no mechanism for passing any auxiliary data (such as a zone name)to DateTimeParseError, and these errors seemed to really need it.Up to now it didn't matter that much just where the error got thrown,but now we'd like to have a hard policy that datetime parse errorsget thrown from just the one place.Hence, invent a "DateTimeErrorExtra" struct that can be used tocarry any extra values needed for specific DTERR codes. Perhapsin the future somebody will be motivated to use this to improvethe specificity of other DateTimeParseError messages, but for nowjust deal with the timezone-error cases.This is on the way to making the datetime input functions reportparse errors softly; but it's really an independent change, socommit separately.Discussion:https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
1 parentfc7852c commit2661469

File tree

7 files changed

+176
-90
lines changed

7 files changed

+176
-90
lines changed

‎contrib/adminpack/adminpack.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
553553
fsec_tfsec;
554554
inttz=0;
555555
structpg_tmdate;
556+
DateTimeErrorExtraextra;
556557

557558
/*
558559
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
@@ -571,7 +572,8 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
571572
if (ParseDateTime(timestampbuf,lowstr,MAXDATELEN,field,ftype,MAXDATEFIELDS,&nf))
572573
continue;
573574

574-
if (DecodeDateTime(field,ftype,nf,&dtype,&date,&fsec,&tz))
575+
if (DecodeDateTime(field,ftype,nf,
576+
&dtype,&date,&fsec,&tz,&extra))
575577
continue;
576578

577579
/* Seems the timestamp is OK; prepare and return tuple */

‎src/backend/access/transam/xlogrecovery.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4790,12 +4790,14 @@ check_recovery_target_time(char **newval, void **extra, GucSource source)
47904790
char*field[MAXDATEFIELDS];
47914791
intftype[MAXDATEFIELDS];
47924792
charworkbuf[MAXDATELEN+MAXDATEFIELDS];
4793+
DateTimeErrorExtradtextra;
47934794
TimestampTztimestamp;
47944795

47954796
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
47964797
field,ftype,MAXDATEFIELDS,&nf);
47974798
if (dterr==0)
4798-
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tz);
4799+
dterr=DecodeDateTime(field,ftype,nf,
4800+
&dtype,tm,&fsec,&tz,&dtextra);
47994801
if (dterr!=0)
48004802
return false;
48014803
if (dtype!=DTK_DATE)

‎src/backend/utils/adt/date.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,15 @@ date_in(PG_FUNCTION_ARGS)
122122
char*field[MAXDATEFIELDS];
123123
intftype[MAXDATEFIELDS];
124124
charworkbuf[MAXDATELEN+1];
125+
DateTimeErrorExtraextra;
125126

126127
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
127128
field,ftype,MAXDATEFIELDS,&nf);
128129
if (dterr==0)
129-
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tzp);
130+
dterr=DecodeDateTime(field,ftype,nf,
131+
&dtype,tm,&fsec,&tzp,&extra);
130132
if (dterr!=0)
131-
DateTimeParseError(dterr,str,"date");
133+
DateTimeParseError(dterr,&extra,str,"date");
132134

133135
switch (dtype)
134136
{
@@ -148,7 +150,7 @@ date_in(PG_FUNCTION_ARGS)
148150
PG_RETURN_DATEADT(date);
149151

150152
default:
151-
DateTimeParseError(DTERR_BAD_FORMAT,str,"date");
153+
DateTimeParseError(DTERR_BAD_FORMAT,&extra,str,"date");
152154
break;
153155
}
154156

@@ -1398,13 +1400,15 @@ time_in(PG_FUNCTION_ARGS)
13981400
char*field[MAXDATEFIELDS];
13991401
intdtype;
14001402
intftype[MAXDATEFIELDS];
1403+
DateTimeErrorExtraextra;
14011404

14021405
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
14031406
field,ftype,MAXDATEFIELDS,&nf);
14041407
if (dterr==0)
1405-
dterr=DecodeTimeOnly(field,ftype,nf,&dtype,tm,&fsec,&tz);
1408+
dterr=DecodeTimeOnly(field,ftype,nf,
1409+
&dtype,tm,&fsec,&tz,&extra);
14061410
if (dterr!=0)
1407-
DateTimeParseError(dterr,str,"time");
1411+
DateTimeParseError(dterr,&extra,str,"time");
14081412

14091413
tm2time(tm,fsec,&result);
14101414
AdjustTimeForTypmod(&result,typmod);
@@ -2284,13 +2288,15 @@ timetz_in(PG_FUNCTION_ARGS)
22842288
char*field[MAXDATEFIELDS];
22852289
intdtype;
22862290
intftype[MAXDATEFIELDS];
2291+
DateTimeErrorExtraextra;
22872292

22882293
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
22892294
field,ftype,MAXDATEFIELDS,&nf);
22902295
if (dterr==0)
2291-
dterr=DecodeTimeOnly(field,ftype,nf,&dtype,tm,&fsec,&tz);
2296+
dterr=DecodeTimeOnly(field,ftype,nf,
2297+
&dtype,tm,&fsec,&tz,&extra);
22922298
if (dterr!=0)
2293-
DateTimeParseError(dterr,str,"time with time zone");
2299+
DateTimeParseError(dterr,&extra,str,"time with time zone");
22942300

22952301
result= (TimeTzADT*)palloc(sizeof(TimeTzADT));
22962302
tm2timetz(tm,fsec,tz,result);
@@ -3042,9 +3048,11 @@ timetz_zone(PG_FUNCTION_ARGS)
30423048
inttz;
30433049
chartzname[TZ_STRLEN_MAX+1];
30443050
char*lowzone;
3045-
inttype,
3051+
intdterr,
3052+
type,
30463053
val;
30473054
pg_tz*tzp;
3055+
DateTimeErrorExtraextra;
30483056

30493057
/*
30503058
* Look up the requested timezone. First we look in the timezone
@@ -3061,7 +3069,9 @@ timetz_zone(PG_FUNCTION_ARGS)
30613069
strlen(tzname),
30623070
false);
30633071

3064-
type=DecodeTimezoneAbbrev(0,lowzone,&val,&tzp);
3072+
dterr=DecodeTimezoneAbbrev(0,lowzone,&type,&val,&tzp,&extra);
3073+
if (dterr)
3074+
DateTimeParseError(dterr,&extra,NULL,NULL);
30653075

30663076
if (type==TZ||type==DTZ)
30673077
{

‎src/backend/utils/adt/datetime.c

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ static intDetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp,
6969
staticboolDetermineTimeZoneAbbrevOffsetInternal(pg_time_tt,
7070
constchar*abbr,pg_tz*tzp,
7171
int*offset,int*isdst);
72-
staticpg_tz*FetchDynamicTimeZone(TimeZoneAbbrevTable*tbl,constdatetkn*tp);
72+
staticpg_tz*FetchDynamicTimeZone(TimeZoneAbbrevTable*tbl,constdatetkn*tp,
73+
DateTimeErrorExtra*extra);
7374

7475

7576
constintday_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
*/
973977
int
974978
DecodeDateTime(char**field,int*ftype,intnf,
975-
int*dtype,structpg_tm*tm,fsec_t*fsec,int*tzp)
979+
int*dtype,structpg_tm*tm,fsec_t*fsec,int*tzp,
980+
DateTimeErrorExtra*extra)
976981
{
977982
intfmask=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+
returnDTERR_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
caseDTK_STRING:
13771375
caseDTK_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+
returndterr;
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
*/
19231927
int
19241928
DecodeTimeOnly(char**field,int*ftype,intnf,
1925-
int*dtype,structpg_tm*tm,fsec_t*fsec,int*tzp)
1929+
int*dtype,structpg_tm*tm,fsec_t*fsec,int*tzp,
1930+
DateTimeErrorExtra*extra)
19261931
{
19271932
intfmask=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+
returnDTERR_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
caseDTK_STRING:
22792277
caseDTK_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+
returndterr;
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
*/
32253232
int
32263233
DecodeTimezoneAbbrev(intfield,constchar*lowtoken,
3227-
int*offset,pg_tz**tz)
3234+
int*ftype,int*offset,pg_tz**tz,
3235+
DateTimeErrorExtra*extra)
32283236
{
3229-
inttype;
32303237
constdatetkn*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+
returnDTERR_BAD_ZONE_ABBREV;
32563265
}
32573266
else
32583267
{
@@ -3261,7 +3270,7 @@ DecodeTimezoneAbbrev(int field, const char *lowtoken,
32613270
}
32623271
}
32633272

3264-
returntype;
3273+
return0;
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
*/
40244038
void
4025-
DateTimeParseError(intdterr,constchar*str,constchar*datatype)
4039+
DateTimeParseError(intdterr,DateTimeErrorExtra*extra,
4040+
constchar*str,constchar*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+
caseDTERR_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+
caseDTERR_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
caseDTERR_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
*/
48844915
staticpg_tz*
4885-
FetchDynamicTimeZone(TimeZoneAbbrevTable*tbl,constdatetkn*tp)
4916+
FetchDynamicTimeZone(TimeZoneAbbrevTable*tbl,constdatetkn*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
returndtza->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+
DateTimeErrorExtraextra;
49965023
TimestampTznow;
49975024
intisdst;
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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp