8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:03:02 +01:00

Fallback for problem converting time-tz/timestamp-tz when ICU is not present in client.

This commit is contained in:
Adriano dos Santos Fernandes 2019-07-14 21:31:17 -03:00
parent 2bc5097252
commit d046a2ca86
7 changed files with 103 additions and 40 deletions

View File

@ -103,6 +103,8 @@ void encodeTimeStampTz(
);
```
When `decodeTimeTz` / `decodeTimeStampTz` is called with non-null `timeZoneBuffer` and ICU could not be loaded in the client, `timeZoneBuffer` returns the string `GMT*` and the others fields receives the timestamp GMT values.
## Time zone string syntax
```

View File

@ -189,6 +189,8 @@ static InitInstance<TimeZoneStartup> timeZoneStartup;
//-------------------------------------
const char TimeZoneUtil::GMT_FALLBACK[5] = "GMT*";
// Return the current user's time zone.
USHORT TimeZoneUtil::getSystemTimeZone()
{
@ -498,7 +500,7 @@ ISC_TIMESTAMP TimeZoneUtil::timeStampTzToTimeStamp(const ISC_TIMESTAMP_TZ& timeS
struct tm times;
int fractions;
decodeTimeStamp(tempTimeStampTz, &times, &fractions);
decodeTimeStamp(tempTimeStampTz, false, &times, &fractions);
return TimeStamp::encode_timestamp(&times, fractions);
}
@ -595,16 +597,39 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
timeStampTz.utc_timestamp.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
}
void TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, Callbacks* cb, struct tm* times, int* fractions)
bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callbacks* cb,
struct tm* times, int* fractions)
{
ISC_TIMESTAMP_TZ timeStampTz = cvtTimeTzToTimeStampTz(timeTz, cb);
decodeTimeStamp(timeStampTz, times, fractions);
bool tzLookup = true;
ISC_TIMESTAMP_TZ timeStampTz;
try
{
timeStampTz = cvtTimeTzToTimeStampTz(timeTz, cb);
}
catch (const Exception&)
{
if (gmtFallback)
{
tzLookup = false;
timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE;
timeStampTz.utc_timestamp = cb->getCurrentGmtTimeStamp();
timeStampTz.utc_timestamp.timestamp_time = timeTz.utc_time;
}
else
throw;
}
void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct tm* times, int* fractions)
decodeTimeStamp(timeStampTz, false, times, fractions);
return tzLookup;
}
bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback,
struct tm* times, int* fractions)
{
SINT64 ticks = timeStampTz.utc_timestamp.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
timeStampTz.utc_timestamp.timestamp_time;
bool icuFail = false;
int displacement;
if (timeStampTz.time_zone == GMT_ZONE)
@ -615,6 +640,8 @@ void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct t
{
UErrorCode icuErrorCode = U_ZERO_ERROR;
try
{
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
@ -642,6 +669,17 @@ void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct t
icuLib.ucalClose(icuCalendar);
}
catch (const Exception&)
{
if (gmtFallback)
{
icuFail = true;
displacement = 0;
}
else
throw;
}
}
ticks += displacement * 60 * ISC_TIME_SECONDS_PRECISION;
@ -650,6 +688,8 @@ void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct t
ts.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
TimeStamp::decode_timestamp(ts, times, fractions);
return !icuFail;
}
ISC_TIMESTAMP_TZ TimeZoneUtil::getCurrentSystemTimeStamp()

View File

@ -59,8 +59,9 @@ public:
};
public:
static const USHORT GMT_ZONE = 65535;
static const char GMT_FALLBACK[5]; // "GMT*"
static const USHORT GMT_ZONE = 65535;
static const unsigned MAX_LEN = 32;
static const unsigned MAX_SIZE = MAX_LEN + 1;
@ -99,8 +100,10 @@ public:
static void localTimeStampToUtc(ISC_TIMESTAMP& timeStamp, Callbacks* cb);
static void localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz);
static void decodeTime(const ISC_TIME_TZ& timeTz, Callbacks* cb, struct tm* times, int* fractions = NULL);
static void decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct tm* times, int* fractions = NULL);
static bool decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callbacks* cb,
struct tm* times, int* fractions = NULL);
static bool decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback,
struct tm* times, int* fractions = NULL);
static ISC_TIMESTAMP_TZ getCurrentSystemTimeStamp();
static ISC_TIMESTAMP_TZ getCurrentGmtTimeStamp();

View File

@ -2208,6 +2208,7 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
// Convert a date or time value into a timestamp for manipulation
bool tzLookup = true;
tm times;
memset(&times, 0, sizeof(struct tm));
@ -2222,7 +2223,7 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
break;
case dtype_sql_time_tz:
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address, cb, &times, &fractions);
tzLookup = TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address, true, cb, &times, &fractions);
timezone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
break;
@ -2237,7 +2238,7 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
case dtype_timestamp_tz:
cb->isVersion4(version4); // Used in the conversion to text some lines below.
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, &times, &fractions);
tzLookup = TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, true, &times, &fractions);
timezone = ((ISC_TIMESTAMP_TZ*) from->dsc_address)->time_zone;
break;
@ -2302,7 +2303,13 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
if (from->dsc_dtype == dtype_sql_time_tz || from->dsc_dtype == dtype_timestamp_tz)
{
*p++ = ' ';
if (tzLookup)
p += TimeZoneUtil::format(p, sizeof(temp) - (p - temp), timezone);
else
{
strncpy(p, TimeZoneUtil::GMT_FALLBACK, sizeof(temp) - (p - temp));
p += strlen(TimeZoneUtil::GMT_FALLBACK);
}
}
// Move the text version of the date/time value into the destination
@ -3455,7 +3462,7 @@ namespace
ISC_TIMESTAMP CommonCallbacks::getCurrentGmtTimeStamp()
{
return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentSystemTimeStamp(), TimeZoneUtil::GMT_ZONE);
return TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
}
USHORT CommonCallbacks::getSessionTimeZone()

View File

@ -5448,7 +5448,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_second:
case blr_extract_millisecond:
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) value->dsc_address,
&EngineCallbacks::instance, &times, &fractions);
false, &EngineCallbacks::instance, &times, &fractions);
break;
case blr_extract_timezone_hour:
@ -5508,7 +5508,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
break;
default:
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, &times, &fractions);
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, false, &times, &fractions);
}
break;

View File

@ -3785,7 +3785,7 @@ dsc* evlFirstLastDay(thread_db* tdbb, const SysFunction* function, const NestVal
break;
case dtype_timestamp_tz:
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, &times, &fractions);
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, false, &times, &fractions);
break;
default:

View File

@ -674,7 +674,8 @@ void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ*
{
tm times;
int intFractions;
TimeZoneUtil::decodeTime(*timeTz, CVT_commonCallbacks, &times, &intFractions);
bool tzLookup = TimeZoneUtil::decodeTime(*timeTz, timeZoneBuffer != nullptr, CVT_commonCallbacks,
&times, &intFractions);
if (hours)
*hours = times.tm_hour;
@ -689,7 +690,12 @@ void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ*
*fractions = (unsigned) intFractions;
if (timeZoneBuffer)
{
if (tzLookup)
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeTz->time_zone);
else
strncpy(timeZoneBuffer, TimeZoneUtil::GMT_FALLBACK, timeZoneBufferLength);
}
}
catch (const Exception& ex)
{
@ -720,7 +726,7 @@ void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIME
{
tm times;
int intFractions;
TimeZoneUtil::decodeTimeStamp(*timeStampTz, &times, &intFractions);
bool tzLookup = TimeZoneUtil::decodeTimeStamp(*timeStampTz, timeZoneBuffer != nullptr, &times, &intFractions);
if (year)
*year = times.tm_year + 1900;
@ -744,7 +750,12 @@ void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIME
*fractions = (unsigned) intFractions;
if (timeZoneBuffer)
{
if (tzLookup)
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeStampTz->time_zone);
else
strncpy(timeZoneBuffer, TimeZoneUtil::GMT_FALLBACK, timeZoneBufferLength);
}
}
catch (const Exception& ex)
{