mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
Fixed CORE-6427 and CORE-6429:
- CORE-6427 - Whitespace as date separator causes conversion error. - CORE-6429 - Timezone offset in timestamp/time literal and CAST should follow SQL standard syntax only.
This commit is contained in:
parent
7b0a29d0bc
commit
ff37d445ce
@ -21,10 +21,10 @@ a routine that changes the current time zone and later run `SET TIME ZONE LOCAL`
|
||||
to its initially received value.
|
||||
|
||||
A time zone may be a string with a time zone region (for example, `America/Sao_Paulo`) or a hours:minutes displacement
|
||||
(for example, `-03:00` or `+3`) from GMT.
|
||||
(for example, `-03:00` or `+3:0`) from GMT.
|
||||
|
||||
A time/timestamp with time zone is considered equal to another time/timestamp with time zone if their conversion to UTC
|
||||
are equal, for example, `time '10:00 -02' = time '09:00 -03'`, since both are the same as `time '12:00 GMT'`.
|
||||
are equal, for example, `time '10:00 -02:00' = time '09:00 -03:00'`, since both are the same as `time '12:00 GMT'`.
|
||||
This is also valid in the context of `UNIQUE` constraints and for sorting purposes.
|
||||
|
||||
Some timestamps does not exist (DST starting) or repeats twice (DST ending). For the first case, when DST starts
|
||||
@ -85,8 +85,8 @@ The time/timestamp parts are stored in UTC (translated from the informed time zo
|
||||
Time zone identifiers (from regions) are put directly in the time_zone field.
|
||||
They start from 65535 (which is the GMT code) and are decreasing as new time zones were/are added.
|
||||
|
||||
Time zone displacements (+/- HH:MM) are encoded with `(sign * (HH * 60 + MM)) + 1439`.
|
||||
For example, a `00:00` displacement is encoded as `(1 * (0 * 60 + 0)) + 1439 = 1439` and `-02:00` as `(-1 * (2 * 60 + 0)) + 1439 = 1319`.
|
||||
Time zone displacements (+/- hours:minutes) are encoded with `(sign * (hours * 60 + minutes)) + 1439`.
|
||||
For example, a `+00:00` displacement is encoded as `(1 * (0 * 60 + 0)) + 1439 = 1439` and `-02:00` as `(-1 * (2 * 60 + 0)) + 1439 = 1319`.
|
||||
|
||||
EXTENDED TIME/TIMESTAMP WITH TIME ZONE have additionally more 2 bytes always containing absolute
|
||||
time zone offset in minutes.
|
||||
@ -215,16 +215,16 @@ fields are set using specified `ext_offset`.
|
||||
|
||||
<time zone> ::=
|
||||
<time zone region> |
|
||||
[+/-] <hour displacement> [: <minute displacement>]
|
||||
{+ | -} <hours displacement> : <minutes displacement>
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
- `'America/Sao_Paulo'`
|
||||
- `'-02:00'`
|
||||
- `'+04'`
|
||||
- `'04:00'`
|
||||
- `'04:30'`
|
||||
- `'+04:00'`
|
||||
- `'+4:0'`
|
||||
- `'-04:30'`
|
||||
|
||||
## `TIME WITH TIME ZONE` and `TIMESTAMP WITH TIME ZONE` literals
|
||||
|
||||
@ -239,9 +239,9 @@ Examples:
|
||||
Examples:
|
||||
|
||||
- `time '10:00 America/Los_Angeles'`
|
||||
- `time '10:00:00.5 +08'`
|
||||
- `time '10:00:00.5 +08:00'`
|
||||
- `timestamp '2018-01-01 10:00 America/Los_Angeles'`
|
||||
- `timestamp '2018-01-01 10:00:00.5 +08'`
|
||||
- `timestamp '2018-01-01 10:00:00.5 +08:00'`
|
||||
|
||||
## Statements and expressions
|
||||
|
||||
@ -281,7 +281,7 @@ If `LOCAL` is used, the value is converted to the session time zone.
|
||||
#### Examples
|
||||
|
||||
```
|
||||
select time '12:00 GMT' at time zone '-03'
|
||||
select time '12:00 GMT' at time zone '-03:00'
|
||||
from rdb$database;
|
||||
|
||||
select current_timestamp at time zone 'America/Sao_Paulo'
|
||||
@ -362,7 +362,7 @@ Returns:
|
||||
```
|
||||
DATABASE_VERSION
|
||||
================
|
||||
2017c
|
||||
2020d
|
||||
```
|
||||
|
||||
### Procedure `TRANSITIONS`
|
||||
|
@ -428,39 +428,40 @@ USHORT TimeZoneUtil::parse(const char* str, unsigned strLen)
|
||||
|
||||
skipSpaces(p, end);
|
||||
|
||||
int sign = 1;
|
||||
bool signPresent = false;
|
||||
const auto start = str;
|
||||
|
||||
if (p < end && (*p == '-' || *p == '+'))
|
||||
{
|
||||
signPresent = true;
|
||||
sign = *p == '-' ? -1 : 1;
|
||||
++p;
|
||||
int sign = *p++ == '-' ? -1 : 1;
|
||||
skipSpaces(p, end);
|
||||
}
|
||||
|
||||
if (p < end && (signPresent || (*p >= '0' && *p <= '9')))
|
||||
{
|
||||
int tzh = parseNumber(p, end);
|
||||
int tzm = 0;
|
||||
|
||||
skipSpaces(p, end);
|
||||
|
||||
if (p < end && *p == ':')
|
||||
if (tzh >= 0)
|
||||
{
|
||||
++p;
|
||||
skipSpaces(p, end);
|
||||
tzm = (unsigned) parseNumber(p, end);
|
||||
skipSpaces(p, end);
|
||||
|
||||
if (p < end && *p == ':')
|
||||
{
|
||||
++p;
|
||||
skipSpaces(p, end);
|
||||
int tzm = parseNumber(p, end);
|
||||
|
||||
if (tzm >= 0)
|
||||
{
|
||||
skipSpaces(p, end);
|
||||
|
||||
if (p == end)
|
||||
return makeFromOffset(sign, tzh, tzm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p != end)
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << string(str, strLen));
|
||||
|
||||
return makeFromOffset(sign, tzh, tzm);
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << string(start, end));
|
||||
return 0; // avoid warning
|
||||
}
|
||||
else
|
||||
return parseRegion(p, str + strLen - p);
|
||||
|
||||
return parseRegion(p, str + strLen - p);
|
||||
}
|
||||
|
||||
// Parses a time zone id from a region string.
|
||||
@ -497,7 +498,7 @@ USHORT TimeZoneUtil::parseRegion(const char* str, unsigned strLen)
|
||||
return id;
|
||||
}
|
||||
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_region) << string(start, len));
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_region) << string(start, end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1178,7 +1179,7 @@ static int parseNumber(const char*& p, const char* end)
|
||||
n = n * 10 + *p++ - '0';
|
||||
|
||||
if (p == start)
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << string(start, end - start));
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -752,9 +752,14 @@ void CVT_string_to_datetime(const dsc* desc,
|
||||
|
||||
components[i] = n;
|
||||
|
||||
bool hadSpace = false;
|
||||
|
||||
// Grab whitespace following the number
|
||||
while (p < end && (*p == ' ' || *p == '\t'))
|
||||
{
|
||||
p++;
|
||||
hadSpace = true;
|
||||
}
|
||||
|
||||
if (p == end)
|
||||
break;
|
||||
@ -762,18 +767,16 @@ void CVT_string_to_datetime(const dsc* desc,
|
||||
// Grab a separator character
|
||||
if (i <= 1)
|
||||
{
|
||||
if (date_sep == '\0' || *p == date_sep)
|
||||
if (date_sep == '\0' || (date_sep != ' ' && *p == date_sep) || (date_sep == ' ' && hadSpace))
|
||||
{
|
||||
date_sep = *p;
|
||||
|
||||
if (*p == '/' || *p == '-')
|
||||
if (date_sep != ' ' && (*p == '/' || *p == '-' || *p == '.'))
|
||||
{
|
||||
p++;
|
||||
date_sep = *p++;
|
||||
continue;
|
||||
}
|
||||
else if (*p == '.')
|
||||
else if (hadSpace)
|
||||
{
|
||||
p++;
|
||||
date_sep = ' ';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -917,7 +917,7 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545210, "Plugin @1:"}, /* plugin_name */
|
||||
{335545211, "PARAMETER @1"}, /* parameter_name */
|
||||
{335545212, "Starting page number for file @1 must be @2 or greater"}, /* file_starting_page_err */
|
||||
{335545213, "Invalid time zone offset: @1 - must be between -14:00 and +14:00"}, /* invalid_timezone_offset */
|
||||
{335545213, "Invalid time zone offset: @1 - must use format +/-hours:minutes and be between -14:00 and +14:00"}, /* invalid_timezone_offset */
|
||||
{335545214, "Invalid time zone region: @1"}, /* invalid_timezone_region */
|
||||
{335545215, "Invalid time zone ID: @1"}, /* invalid_timezone_id */
|
||||
{335545216, "Wrong base64 text length @1, should be multiple of 4"}, /* tom_decode64len */
|
||||
|
@ -1000,7 +1000,7 @@ Data source : @4', NULL, NULL)
|
||||
('plugin_name', NULL, 'CryptoManager.cpp', NULL, 0, 890, NULL, 'Plugin @1:', NULL, NULL);
|
||||
('parameter_name', 'ProcedureManager::checkDependencies', 'dfw.e', NULL, 0, 891, NULL, 'PARAMETER @1', NULL, NULL);
|
||||
('file_starting_page_err', 'add_file', 'dfw.epp', NULL, 0, 892, NULL, 'Starting page number for file @1 must be @2 or greater', NULL, NULL);
|
||||
('invalid_timezone_offset', NULL, 'TimeZoneUtil.cpp', NULL, 0, 893, NULL, 'Invalid time zone offset: @1 - must be between -14:00 and +14:00', NULL, NULL);
|
||||
('invalid_timezone_offset', NULL, 'TimeZoneUtil.cpp', NULL, 0, 893, NULL, 'Invalid time zone offset: @1 - must use format +/-hours:minutes and be between -14:00 and +14:00', NULL, NULL);
|
||||
('invalid_timezone_region', NULL, 'TimeZoneUtil.cpp', NULL, 0, 894, NULL, 'Invalid time zone region: @1', NULL, NULL);
|
||||
('invalid_timezone_id', NULL, 'TimeZoneUtil.cpp', NULL, 0, 895, NULL, 'Invalid time zone ID: @1', NULL, NULL);
|
||||
('tom_decode64len', NULL, 'SysFunction.cpp', NULL, 0, 896, NULL, 'Wrong base64 text length @1, should be multiple of 4', NULL, NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user