mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
Allow DateTimeParseError to handle bad-timezone error messages.
Pay down some ancient technical debt (dating to commit 022fd9966
):
fix a couple of places in datetime parsing that were throwing
ereport's immediately instead of returning a DTERR code that could be
interpreted by DateTimeParseError. The reason for that was that there
was 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 errors
get thrown from just the one place.
Hence, invent a "DateTimeErrorExtra" struct that can be used to
carry any extra values needed for specific DTERR codes. Perhaps
in the future somebody will be motivated to use this to improve
the specificity of other DateTimeParseError messages, but for now
just deal with the timezone-error cases.
This is on the way to making the datetime input functions report
parse errors softly; but it's really an independent change, so
commit separately.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
This commit is contained in:
parent
fc7852c6cb
commit
2661469d86
@ -553,6 +553,7 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
|
|||||||
fsec_t fsec;
|
fsec_t fsec;
|
||||||
int tz = 0;
|
int tz = 0;
|
||||||
struct pg_tm date;
|
struct pg_tm date;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
|
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
|
||||||
@ -571,7 +572,8 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
|
|||||||
if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
|
if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
|
if (DecodeDateTime(field, ftype, nf,
|
||||||
|
&dtype, &date, &fsec, &tz, &extra))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Seems the timestamp is OK; prepare and return tuple */
|
/* Seems the timestamp is OK; prepare and return tuple */
|
||||||
|
@ -4790,12 +4790,14 @@ check_recovery_target_time(char **newval, void **extra, GucSource source)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
||||||
|
DateTimeErrorExtra dtextra;
|
||||||
TimestampTz timestamp;
|
TimestampTz timestamp;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tz, &dtextra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
return false;
|
return false;
|
||||||
if (dtype != DTK_DATE)
|
if (dtype != DTK_DATE)
|
||||||
|
@ -122,13 +122,15 @@ date_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char workbuf[MAXDATELEN + 1];
|
char workbuf[MAXDATELEN + 1];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
|
dterr = DecodeDateTime(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tzp, &extra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
DateTimeParseError(dterr, str, "date");
|
DateTimeParseError(dterr, &extra, str, "date");
|
||||||
|
|
||||||
switch (dtype)
|
switch (dtype)
|
||||||
{
|
{
|
||||||
@ -148,7 +150,7 @@ date_in(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_DATEADT(date);
|
PG_RETURN_DATEADT(date);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
|
DateTimeParseError(DTERR_BAD_FORMAT, &extra, str, "date");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1398,13 +1400,15 @@ time_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int dtype;
|
int dtype;
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeTimeOnly(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tz, &extra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
DateTimeParseError(dterr, str, "time");
|
DateTimeParseError(dterr, &extra, str, "time");
|
||||||
|
|
||||||
tm2time(tm, fsec, &result);
|
tm2time(tm, fsec, &result);
|
||||||
AdjustTimeForTypmod(&result, typmod);
|
AdjustTimeForTypmod(&result, typmod);
|
||||||
@ -2284,13 +2288,15 @@ timetz_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int dtype;
|
int dtype;
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeTimeOnly(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tz, &extra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
DateTimeParseError(dterr, str, "time with time zone");
|
DateTimeParseError(dterr, &extra, str, "time with time zone");
|
||||||
|
|
||||||
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
||||||
tm2timetz(tm, fsec, tz, result);
|
tm2timetz(tm, fsec, tz, result);
|
||||||
@ -3042,9 +3048,11 @@ timetz_zone(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int dterr,
|
||||||
|
type,
|
||||||
val;
|
val;
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the requested timezone. First we look in the timezone
|
* Look up the requested timezone. First we look in the timezone
|
||||||
@ -3061,7 +3069,9 @@ timetz_zone(PG_FUNCTION_ARGS)
|
|||||||
strlen(tzname),
|
strlen(tzname),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
dterr = DecodeTimezoneAbbrev(0, lowzone, &type, &val, &tzp, &extra);
|
||||||
|
if (dterr)
|
||||||
|
DateTimeParseError(dterr, &extra, NULL, NULL);
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,8 @@ static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp,
|
|||||||
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t,
|
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t,
|
||||||
const char *abbr, pg_tz *tzp,
|
const char *abbr, pg_tz *tzp,
|
||||||
int *offset, int *isdst);
|
int *offset, int *isdst);
|
||||||
static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
|
static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp,
|
||||||
|
DateTimeErrorExtra *extra);
|
||||||
|
|
||||||
|
|
||||||
const int day_tab[2][13] =
|
const int day_tab[2][13] =
|
||||||
@ -951,6 +952,9 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
|||||||
* Return 0 if full date, 1 if only time, and negative DTERR code if problems.
|
* Return 0 if full date, 1 if only time, and negative DTERR code if problems.
|
||||||
* (Currently, all callers treat 1 as an error return too.)
|
* (Currently, all callers treat 1 as an error return too.)
|
||||||
*
|
*
|
||||||
|
* Inputs are field[] and ftype[] arrays, of length nf.
|
||||||
|
* Other arguments are outputs.
|
||||||
|
*
|
||||||
* External format(s):
|
* External format(s):
|
||||||
* "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
|
* "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
|
||||||
* "Fri Feb-7-1997 15:23:27"
|
* "Fri Feb-7-1997 15:23:27"
|
||||||
@ -972,7 +976,8 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
DecodeDateTime(char **field, int *ftype, int nf,
|
DecodeDateTime(char **field, int *ftype, int nf,
|
||||||
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
|
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp,
|
||||||
|
DateTimeErrorExtra *extra)
|
||||||
{
|
{
|
||||||
int fmask = 0,
|
int fmask = 0,
|
||||||
tmask,
|
tmask,
|
||||||
@ -1112,15 +1117,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
|
|||||||
namedTz = pg_tzset(field[i]);
|
namedTz = pg_tzset(field[i]);
|
||||||
if (!namedTz)
|
if (!namedTz)
|
||||||
{
|
{
|
||||||
/*
|
extra->dtee_timezone = field[i];
|
||||||
* We should return an error code instead of
|
return DTERR_BAD_TIMEZONE;
|
||||||
* ereport'ing directly, but then there is no way
|
|
||||||
* to report the bad time zone name.
|
|
||||||
*/
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("time zone \"%s\" not recognized",
|
|
||||||
field[i])));
|
|
||||||
}
|
}
|
||||||
/* we'll apply the zone setting below */
|
/* we'll apply the zone setting below */
|
||||||
tmask = DTK_M(TZ);
|
tmask = DTK_M(TZ);
|
||||||
@ -1376,7 +1374,10 @@ DecodeDateTime(char **field, int *ftype, int nf,
|
|||||||
case DTK_STRING:
|
case DTK_STRING:
|
||||||
case DTK_SPECIAL:
|
case DTK_SPECIAL:
|
||||||
/* timezone abbrevs take precedence over built-in tokens */
|
/* timezone abbrevs take precedence over built-in tokens */
|
||||||
type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
|
dterr = DecodeTimezoneAbbrev(i, field[i],
|
||||||
|
&type, &val, &valtz, extra);
|
||||||
|
if (dterr)
|
||||||
|
return dterr;
|
||||||
if (type == UNKNOWN_FIELD)
|
if (type == UNKNOWN_FIELD)
|
||||||
type = DecodeSpecial(i, field[i], &val);
|
type = DecodeSpecial(i, field[i], &val);
|
||||||
if (type == IGNORE_DTF)
|
if (type == IGNORE_DTF)
|
||||||
@ -1912,6 +1913,9 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
|
|||||||
* Interpret parsed string as time fields only.
|
* Interpret parsed string as time fields only.
|
||||||
* Returns 0 if successful, DTERR code if bogus input detected.
|
* Returns 0 if successful, DTERR code if bogus input detected.
|
||||||
*
|
*
|
||||||
|
* Inputs are field[] and ftype[] arrays, of length nf.
|
||||||
|
* Other arguments are outputs.
|
||||||
|
*
|
||||||
* Note that support for time zone is here for
|
* Note that support for time zone is here for
|
||||||
* SQL TIME WITH TIME ZONE, but it reveals
|
* SQL TIME WITH TIME ZONE, but it reveals
|
||||||
* bogosity with SQL date/time standards, since
|
* bogosity with SQL date/time standards, since
|
||||||
@ -1922,7 +1926,8 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
DecodeTimeOnly(char **field, int *ftype, int nf,
|
DecodeTimeOnly(char **field, int *ftype, int nf,
|
||||||
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
|
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp,
|
||||||
|
DateTimeErrorExtra *extra)
|
||||||
{
|
{
|
||||||
int fmask = 0,
|
int fmask = 0,
|
||||||
tmask,
|
tmask,
|
||||||
@ -2018,15 +2023,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
|
|||||||
namedTz = pg_tzset(field[i]);
|
namedTz = pg_tzset(field[i]);
|
||||||
if (!namedTz)
|
if (!namedTz)
|
||||||
{
|
{
|
||||||
/*
|
extra->dtee_timezone = field[i];
|
||||||
* We should return an error code instead of
|
return DTERR_BAD_TIMEZONE;
|
||||||
* ereport'ing directly, but then there is no way
|
|
||||||
* to report the bad time zone name.
|
|
||||||
*/
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("time zone \"%s\" not recognized",
|
|
||||||
field[i])));
|
|
||||||
}
|
}
|
||||||
/* we'll apply the zone setting below */
|
/* we'll apply the zone setting below */
|
||||||
ftype[i] = DTK_TZ;
|
ftype[i] = DTK_TZ;
|
||||||
@ -2278,7 +2276,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
|
|||||||
case DTK_STRING:
|
case DTK_STRING:
|
||||||
case DTK_SPECIAL:
|
case DTK_SPECIAL:
|
||||||
/* timezone abbrevs take precedence over built-in tokens */
|
/* timezone abbrevs take precedence over built-in tokens */
|
||||||
type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
|
dterr = DecodeTimezoneAbbrev(i, field[i],
|
||||||
|
&type, &val, &valtz, extra);
|
||||||
|
if (dterr)
|
||||||
|
return dterr;
|
||||||
if (type == UNKNOWN_FIELD)
|
if (type == UNKNOWN_FIELD)
|
||||||
type = DecodeSpecial(i, field[i], &val);
|
type = DecodeSpecial(i, field[i], &val);
|
||||||
if (type == IGNORE_DTF)
|
if (type == IGNORE_DTF)
|
||||||
@ -3211,12 +3212,18 @@ DecodeTimezone(const char *str, int *tzp)
|
|||||||
/* DecodeTimezoneAbbrev()
|
/* DecodeTimezoneAbbrev()
|
||||||
* Interpret string as a timezone abbreviation, if possible.
|
* Interpret string as a timezone abbreviation, if possible.
|
||||||
*
|
*
|
||||||
* Returns an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
|
* Sets *ftype to an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
|
||||||
* string is not any known abbreviation. On success, set *offset and *tz to
|
* string is not any known abbreviation. On success, set *offset and *tz to
|
||||||
* represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
|
* represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
|
||||||
* Note that full timezone names (such as America/New_York) are not handled
|
* Note that full timezone names (such as America/New_York) are not handled
|
||||||
* here, mostly for historical reasons.
|
* here, mostly for historical reasons.
|
||||||
*
|
*
|
||||||
|
* The function result is 0 or a DTERR code; in the latter case, *extra
|
||||||
|
* is filled as needed. Note that unknown-abbreviation is not considered
|
||||||
|
* an error case. Also note that many callers assume that the DTERR code
|
||||||
|
* is one that DateTimeParseError does not require "str" or "datatype"
|
||||||
|
* strings for.
|
||||||
|
*
|
||||||
* Given string must be lowercased already.
|
* Given string must be lowercased already.
|
||||||
*
|
*
|
||||||
* Implement a cache lookup since it is likely that dates
|
* Implement a cache lookup since it is likely that dates
|
||||||
@ -3224,9 +3231,9 @@ DecodeTimezone(const char *str, int *tzp)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
||||||
int *offset, pg_tz **tz)
|
int *ftype, int *offset, pg_tz **tz,
|
||||||
|
DateTimeErrorExtra *extra)
|
||||||
{
|
{
|
||||||
int type;
|
|
||||||
const datetkn *tp;
|
const datetkn *tp;
|
||||||
|
|
||||||
tp = abbrevcache[field];
|
tp = abbrevcache[field];
|
||||||
@ -3241,18 +3248,20 @@ DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
|||||||
}
|
}
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
{
|
{
|
||||||
type = UNKNOWN_FIELD;
|
*ftype = UNKNOWN_FIELD;
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
*tz = NULL;
|
*tz = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
abbrevcache[field] = tp;
|
abbrevcache[field] = tp;
|
||||||
type = tp->type;
|
*ftype = tp->type;
|
||||||
if (type == DYNTZ)
|
if (tp->type == DYNTZ)
|
||||||
{
|
{
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
*tz = FetchDynamicTimeZone(zoneabbrevtbl, tp);
|
*tz = FetchDynamicTimeZone(zoneabbrevtbl, tp, extra);
|
||||||
|
if (*tz == NULL)
|
||||||
|
return DTERR_BAD_ZONE_ABBREV;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3261,7 +3270,7 @@ DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4014,15 +4023,21 @@ DecodeUnits(int field, const char *lowtoken, int *val)
|
|||||||
/*
|
/*
|
||||||
* Report an error detected by one of the datetime input processing routines.
|
* Report an error detected by one of the datetime input processing routines.
|
||||||
*
|
*
|
||||||
* dterr is the error code, str is the original input string, datatype is
|
* dterr is the error code, and *extra contains any auxiliary info we need
|
||||||
* the name of the datatype we were trying to accept.
|
* for the error report. extra can be NULL if not needed for the particular
|
||||||
|
* dterr value.
|
||||||
|
*
|
||||||
|
* str is the original input string, and datatype is the name of the datatype
|
||||||
|
* we were trying to accept. (For some DTERR codes, these are not used and
|
||||||
|
* can be NULL.)
|
||||||
*
|
*
|
||||||
* Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
|
* Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
|
||||||
* DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
|
* DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
|
||||||
* separate SQLSTATE codes, so ...
|
* separate SQLSTATE codes, so ...
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
DateTimeParseError(int dterr, const char *str, const char *datatype)
|
DateTimeParseError(int dterr, DateTimeErrorExtra *extra,
|
||||||
|
const char *str, const char *datatype)
|
||||||
{
|
{
|
||||||
switch (dterr)
|
switch (dterr)
|
||||||
{
|
{
|
||||||
@ -4052,6 +4067,20 @@ DateTimeParseError(int dterr, const char *str, const char *datatype)
|
|||||||
errmsg("time zone displacement out of range: \"%s\"",
|
errmsg("time zone displacement out of range: \"%s\"",
|
||||||
str)));
|
str)));
|
||||||
break;
|
break;
|
||||||
|
case DTERR_BAD_TIMEZONE:
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("time zone \"%s\" not recognized",
|
||||||
|
extra->dtee_timezone)));
|
||||||
|
break;
|
||||||
|
case DTERR_BAD_ZONE_ABBREV:
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
|
errmsg("time zone \"%s\" not recognized",
|
||||||
|
extra->dtee_timezone),
|
||||||
|
errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
|
||||||
|
extra->dtee_abbrev)));
|
||||||
|
break;
|
||||||
case DTERR_BAD_FORMAT:
|
case DTERR_BAD_FORMAT:
|
||||||
default:
|
default:
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -4880,9 +4909,12 @@ InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
|
* Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
|
||||||
|
*
|
||||||
|
* On failure, returns NULL and fills *extra for a DTERR_BAD_ZONE_ABBREV error.
|
||||||
*/
|
*/
|
||||||
static pg_tz *
|
static pg_tz *
|
||||||
FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
|
FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp,
|
||||||
|
DateTimeErrorExtra *extra)
|
||||||
{
|
{
|
||||||
DynamicZoneAbbrev *dtza;
|
DynamicZoneAbbrev *dtza;
|
||||||
|
|
||||||
@ -4896,18 +4928,12 @@ FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
|
|||||||
if (dtza->tz == NULL)
|
if (dtza->tz == NULL)
|
||||||
{
|
{
|
||||||
dtza->tz = pg_tzset(dtza->zone);
|
dtza->tz = pg_tzset(dtza->zone);
|
||||||
|
|
||||||
/*
|
|
||||||
* Ideally we'd let the caller ereport instead of doing it here, but
|
|
||||||
* then there is no way to report the bad time zone name.
|
|
||||||
*/
|
|
||||||
if (dtza->tz == NULL)
|
if (dtza->tz == NULL)
|
||||||
ereport(ERROR,
|
{
|
||||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
/* Ooops, bogus zone name in config file entry */
|
||||||
errmsg("time zone \"%s\" not recognized",
|
extra->dtee_timezone = dtza->zone;
|
||||||
dtza->zone),
|
extra->dtee_abbrev = tp->token;
|
||||||
errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
|
}
|
||||||
tp->token)));
|
|
||||||
}
|
}
|
||||||
return dtza->tz;
|
return dtza->tz;
|
||||||
}
|
}
|
||||||
@ -4993,10 +5019,14 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
/* Determine the current meaning of the abbrev */
|
/* Determine the current meaning of the abbrev */
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
TimestampTz now;
|
TimestampTz now;
|
||||||
int isdst;
|
int isdst;
|
||||||
|
|
||||||
tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp);
|
tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp, &extra);
|
||||||
|
if (tzp == NULL)
|
||||||
|
DateTimeParseError(DTERR_BAD_ZONE_ABBREV, &extra,
|
||||||
|
NULL, NULL);
|
||||||
now = GetCurrentTransactionStartTimestamp();
|
now = GetCurrentTransactionStartTimestamp();
|
||||||
gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now,
|
gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now,
|
||||||
tp->token,
|
tp->token,
|
||||||
|
@ -4246,10 +4246,12 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
/* Use the specified time zone, if any. */
|
/* Use the specified time zone, if any. */
|
||||||
if (tm.tm_zone)
|
if (tm.tm_zone)
|
||||||
{
|
{
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
int dterr = DecodeTimezone(tm.tm_zone, &tz);
|
int dterr = DecodeTimezone(tm.tm_zone, &tz);
|
||||||
|
|
||||||
if (dterr)
|
if (dterr)
|
||||||
DateTimeParseError(dterr, text_to_cstring(date_txt), "timestamptz");
|
DateTimeParseError(dterr, &extra, text_to_cstring(date_txt),
|
||||||
|
"timestamptz");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tz = DetermineTimeZoneOffset(&tm, session_timezone);
|
tz = DetermineTimeZoneOffset(&tm, session_timezone);
|
||||||
@ -4343,10 +4345,13 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
|
|||||||
|
|
||||||
if (tm.tm_zone)
|
if (tm.tm_zone)
|
||||||
{
|
{
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
int dterr = DecodeTimezone(tm.tm_zone, tz);
|
int dterr = DecodeTimezone(tm.tm_zone, tz);
|
||||||
|
|
||||||
if (dterr)
|
if (dterr)
|
||||||
DateTimeParseError(dterr, text_to_cstring(date_txt), "timestamptz");
|
DateTimeParseError(dterr, &extra,
|
||||||
|
text_to_cstring(date_txt),
|
||||||
|
"timestamptz");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4429,10 +4434,13 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
|
|||||||
|
|
||||||
if (tm.tm_zone)
|
if (tm.tm_zone)
|
||||||
{
|
{
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
int dterr = DecodeTimezone(tm.tm_zone, tz);
|
int dterr = DecodeTimezone(tm.tm_zone, tz);
|
||||||
|
|
||||||
if (dterr)
|
if (dterr)
|
||||||
RETURN_ERROR(DateTimeParseError(dterr, text_to_cstring(date_txt), "timetz"));
|
RETURN_ERROR(DateTimeParseError(dterr, &extra,
|
||||||
|
text_to_cstring(date_txt),
|
||||||
|
"timetz"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4781,7 +4789,7 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
|
|||||||
* said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
|
* said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
|
||||||
* irrelevant hint about datestyle.
|
* irrelevant hint about datestyle.
|
||||||
*/
|
*/
|
||||||
RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"));
|
RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL, date_str, "timestamp"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4791,7 +4799,7 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
|
|||||||
tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
|
tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
|
||||||
*fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
|
*fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
|
||||||
{
|
{
|
||||||
RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"));
|
RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL, date_str, "timestamp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save parsed time-zone into tm->tm_zone if it was specified */
|
/* Save parsed time-zone into tm->tm_zone if it was specified */
|
||||||
@ -4802,7 +4810,7 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
|
|||||||
if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
|
if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
|
||||||
tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
|
tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
|
||||||
{
|
{
|
||||||
RETURN_ERROR(DateTimeParseError(DTERR_TZDISP_OVERFLOW, date_str, "timestamp"));
|
RETURN_ERROR(DateTimeParseError(DTERR_TZDISP_OVERFLOW, NULL, date_str, "timestamp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
tz = psprintf("%c%02d:%02d",
|
tz = psprintf("%c%02d:%02d",
|
||||||
|
@ -161,13 +161,15 @@ timestamp_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tz, &extra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
DateTimeParseError(dterr, str, "timestamp");
|
DateTimeParseError(dterr, &extra, str, "timestamp");
|
||||||
|
|
||||||
switch (dtype)
|
switch (dtype)
|
||||||
{
|
{
|
||||||
@ -419,13 +421,15 @@ timestamptz_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
char workbuf[MAXDATELEN + MAXDATEFIELDS];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
|
||||||
field, ftype, MAXDATEFIELDS, &nf);
|
field, ftype, MAXDATEFIELDS, &nf);
|
||||||
if (dterr == 0)
|
if (dterr == 0)
|
||||||
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
|
dterr = DecodeDateTime(field, ftype, nf,
|
||||||
|
&dtype, tm, &fsec, &tz, &extra);
|
||||||
if (dterr != 0)
|
if (dterr != 0)
|
||||||
DateTimeParseError(dterr, str, "timestamp with time zone");
|
DateTimeParseError(dterr, &extra, str, "timestamp with time zone");
|
||||||
|
|
||||||
switch (dtype)
|
switch (dtype)
|
||||||
{
|
{
|
||||||
@ -470,7 +474,7 @@ static int
|
|||||||
parse_sane_timezone(struct pg_tm *tm, text *zone)
|
parse_sane_timezone(struct pg_tm *tm, text *zone)
|
||||||
{
|
{
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
int rt;
|
int dterr;
|
||||||
int tz;
|
int tz;
|
||||||
|
|
||||||
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
text_to_cstring_buffer(zone, tzname, sizeof(tzname));
|
||||||
@ -497,19 +501,20 @@ parse_sane_timezone(struct pg_tm *tm, text *zone)
|
|||||||
"numeric time zone", tzname),
|
"numeric time zone", tzname),
|
||||||
errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
|
errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
|
||||||
|
|
||||||
rt = DecodeTimezone(tzname, &tz);
|
dterr = DecodeTimezone(tzname, &tz);
|
||||||
if (rt != 0)
|
if (dterr != 0)
|
||||||
{
|
{
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int type,
|
||||||
val;
|
val;
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
if (rt == DTERR_TZDISP_OVERFLOW)
|
if (dterr == DTERR_TZDISP_OVERFLOW)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("numeric time zone \"%s\" out of range", tzname)));
|
errmsg("numeric time zone \"%s\" out of range", tzname)));
|
||||||
else if (rt != DTERR_BAD_FORMAT)
|
else if (dterr != DTERR_BAD_FORMAT)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("time zone \"%s\" not recognized", tzname)));
|
errmsg("time zone \"%s\" not recognized", tzname)));
|
||||||
@ -518,7 +523,9 @@ parse_sane_timezone(struct pg_tm *tm, text *zone)
|
|||||||
lowzone = downcase_truncate_identifier(tzname,
|
lowzone = downcase_truncate_identifier(tzname,
|
||||||
strlen(tzname),
|
strlen(tzname),
|
||||||
false);
|
false);
|
||||||
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
dterr = DecodeTimezoneAbbrev(0, lowzone, &type, &val, &tzp, &extra);
|
||||||
|
if (dterr)
|
||||||
|
DateTimeParseError(dterr, &extra, NULL, NULL);
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
{
|
{
|
||||||
@ -897,6 +904,7 @@ interval_in(PG_FUNCTION_ARGS)
|
|||||||
char *field[MAXDATEFIELDS];
|
char *field[MAXDATEFIELDS];
|
||||||
int ftype[MAXDATEFIELDS];
|
int ftype[MAXDATEFIELDS];
|
||||||
char workbuf[256];
|
char workbuf[256];
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
itm_in->tm_year = 0;
|
itm_in->tm_year = 0;
|
||||||
itm_in->tm_mon = 0;
|
itm_in->tm_mon = 0;
|
||||||
@ -923,7 +931,7 @@ interval_in(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
if (dterr == DTERR_FIELD_OVERFLOW)
|
if (dterr == DTERR_FIELD_OVERFLOW)
|
||||||
dterr = DTERR_INTERVAL_OVERFLOW;
|
dterr = DTERR_INTERVAL_OVERFLOW;
|
||||||
DateTimeParseError(dterr, str, "interval");
|
DateTimeParseError(dterr, &extra, str, "interval");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (Interval *) palloc(sizeof(Interval));
|
result = (Interval *) palloc(sizeof(Interval));
|
||||||
@ -4291,9 +4299,11 @@ timestamptz_trunc_zone(PG_FUNCTION_ARGS)
|
|||||||
TimestampTz result;
|
TimestampTz result;
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int dterr,
|
||||||
|
type,
|
||||||
val;
|
val;
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timestamptz_zone() doesn't look up the zone for infinite inputs, so we
|
* timestamptz_zone() doesn't look up the zone for infinite inputs, so we
|
||||||
@ -4312,7 +4322,9 @@ timestamptz_trunc_zone(PG_FUNCTION_ARGS)
|
|||||||
strlen(tzname),
|
strlen(tzname),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
dterr = DecodeTimezoneAbbrev(0, lowzone, &type, &val, &tzp, &extra);
|
||||||
|
if (dterr)
|
||||||
|
DateTimeParseError(dterr, &extra, NULL, NULL);
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
{
|
{
|
||||||
@ -5412,9 +5424,11 @@ timestamp_zone(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int dterr,
|
||||||
|
type,
|
||||||
val;
|
val;
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
struct pg_tm tm;
|
struct pg_tm tm;
|
||||||
fsec_t fsec;
|
fsec_t fsec;
|
||||||
|
|
||||||
@ -5436,7 +5450,9 @@ timestamp_zone(PG_FUNCTION_ARGS)
|
|||||||
strlen(tzname),
|
strlen(tzname),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
dterr = DecodeTimezoneAbbrev(0, lowzone, &type, &val, &tzp, &extra);
|
||||||
|
if (dterr)
|
||||||
|
DateTimeParseError(dterr, &extra, NULL, NULL);
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
{
|
{
|
||||||
@ -5666,9 +5682,11 @@ timestamptz_zone(PG_FUNCTION_ARGS)
|
|||||||
int tz;
|
int tz;
|
||||||
char tzname[TZ_STRLEN_MAX + 1];
|
char tzname[TZ_STRLEN_MAX + 1];
|
||||||
char *lowzone;
|
char *lowzone;
|
||||||
int type,
|
int dterr,
|
||||||
|
type,
|
||||||
val;
|
val;
|
||||||
pg_tz *tzp;
|
pg_tz *tzp;
|
||||||
|
DateTimeErrorExtra extra;
|
||||||
|
|
||||||
if (TIMESTAMP_NOT_FINITE(timestamp))
|
if (TIMESTAMP_NOT_FINITE(timestamp))
|
||||||
PG_RETURN_TIMESTAMP(timestamp);
|
PG_RETURN_TIMESTAMP(timestamp);
|
||||||
@ -5688,7 +5706,9 @@ timestamptz_zone(PG_FUNCTION_ARGS)
|
|||||||
strlen(tzname),
|
strlen(tzname),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
|
dterr = DecodeTimezoneAbbrev(0, lowzone, &type, &val, &tzp, &extra);
|
||||||
|
if (dterr)
|
||||||
|
DateTimeParseError(dterr, &extra, NULL, NULL);
|
||||||
|
|
||||||
if (type == TZ || type == DTZ)
|
if (type == TZ || type == DTZ)
|
||||||
{
|
{
|
||||||
|
@ -276,13 +276,25 @@ extern PGDLLIMPORT const int day_tab[2][13];
|
|||||||
* Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc)
|
* Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc)
|
||||||
* return zero or a positive value on success. On failure, they return
|
* return zero or a positive value on success. On failure, they return
|
||||||
* one of these negative code values. DateTimeParseError may be used to
|
* one of these negative code values. DateTimeParseError may be used to
|
||||||
* produce a correct ereport.
|
* produce a suitable error report. For some of these codes,
|
||||||
|
* DateTimeParseError requires additional information, which is carried
|
||||||
|
* in struct DateTimeErrorExtra.
|
||||||
*/
|
*/
|
||||||
#define DTERR_BAD_FORMAT (-1)
|
#define DTERR_BAD_FORMAT (-1)
|
||||||
#define DTERR_FIELD_OVERFLOW (-2)
|
#define DTERR_FIELD_OVERFLOW (-2)
|
||||||
#define DTERR_MD_FIELD_OVERFLOW (-3) /* triggers hint about DateStyle */
|
#define DTERR_MD_FIELD_OVERFLOW (-3) /* triggers hint about DateStyle */
|
||||||
#define DTERR_INTERVAL_OVERFLOW (-4)
|
#define DTERR_INTERVAL_OVERFLOW (-4)
|
||||||
#define DTERR_TZDISP_OVERFLOW (-5)
|
#define DTERR_TZDISP_OVERFLOW (-5)
|
||||||
|
#define DTERR_BAD_TIMEZONE (-6)
|
||||||
|
#define DTERR_BAD_ZONE_ABBREV (-7)
|
||||||
|
|
||||||
|
typedef struct DateTimeErrorExtra
|
||||||
|
{
|
||||||
|
/* Needed for DTERR_BAD_TIMEZONE and DTERR_BAD_ZONE_ABBREV: */
|
||||||
|
const char *dtee_timezone; /* incorrect time zone name */
|
||||||
|
/* Needed for DTERR_BAD_ZONE_ABBREV: */
|
||||||
|
const char *dtee_abbrev; /* relevant time zone abbreviation */
|
||||||
|
} DateTimeErrorExtra;
|
||||||
|
|
||||||
|
|
||||||
extern void GetCurrentDateTime(struct pg_tm *tm);
|
extern void GetCurrentDateTime(struct pg_tm *tm);
|
||||||
@ -293,19 +305,20 @@ extern int date2j(int year, int month, int day);
|
|||||||
extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
|
||||||
char **field, int *ftype,
|
char **field, int *ftype,
|
||||||
int maxfields, int *numfields);
|
int maxfields, int *numfields);
|
||||||
extern int DecodeDateTime(char **field, int *ftype,
|
extern int DecodeDateTime(char **field, int *ftype, int nf,
|
||||||
int nf, int *dtype,
|
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp,
|
||||||
struct pg_tm *tm, fsec_t *fsec, int *tzp);
|
DateTimeErrorExtra *extra);
|
||||||
extern int DecodeTimezone(const char *str, int *tzp);
|
extern int DecodeTimezone(const char *str, int *tzp);
|
||||||
extern int DecodeTimeOnly(char **field, int *ftype,
|
extern int DecodeTimeOnly(char **field, int *ftype, int nf,
|
||||||
int nf, int *dtype,
|
int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp,
|
||||||
struct pg_tm *tm, fsec_t *fsec, int *tzp);
|
DateTimeErrorExtra *extra);
|
||||||
extern int DecodeInterval(char **field, int *ftype, int nf, int range,
|
extern int DecodeInterval(char **field, int *ftype, int nf, int range,
|
||||||
int *dtype, struct pg_itm_in *itm_in);
|
int *dtype, struct pg_itm_in *itm_in);
|
||||||
extern int DecodeISO8601Interval(char *str,
|
extern int DecodeISO8601Interval(char *str,
|
||||||
int *dtype, struct pg_itm_in *itm_in);
|
int *dtype, struct pg_itm_in *itm_in);
|
||||||
|
|
||||||
extern void DateTimeParseError(int dterr, const char *str,
|
extern void DateTimeParseError(int dterr, DateTimeErrorExtra *extra,
|
||||||
|
const char *str,
|
||||||
const char *datatype) pg_attribute_noreturn();
|
const char *datatype) pg_attribute_noreturn();
|
||||||
|
|
||||||
extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp);
|
extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp);
|
||||||
@ -323,7 +336,8 @@ extern int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
|
|||||||
struct pg_tm *tm);
|
struct pg_tm *tm);
|
||||||
|
|
||||||
extern int DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
extern int DecodeTimezoneAbbrev(int field, const char *lowtoken,
|
||||||
int *offset, pg_tz **tz);
|
int *ftype, int *offset, pg_tz **tz,
|
||||||
|
DateTimeErrorExtra *extra);
|
||||||
extern int DecodeSpecial(int field, const char *lowtoken, int *val);
|
extern int DecodeSpecial(int field, const char *lowtoken, int *val);
|
||||||
extern int DecodeUnits(int field, const char *lowtoken, int *val);
|
extern int DecodeUnits(int field, const char *lowtoken, int *val);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user