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

Merge branch 'work/time-zone-support-mon'

This commit is contained in:
Adriano dos Santos Fernandes 2018-12-29 15:38:22 -02:00
commit ee05dbf7b9
41 changed files with 384 additions and 167 deletions

View File

@ -706,6 +706,17 @@
#
#DummyPacketInterval = 0
#
# Default session or client time zone.
#
# If empty, the default is the OS time zone.
# When set in the server, it defines the default session time zone for attachments.
# When set in the client, it defines the default time zone used with client-side API functions.
#
# Type: string
#
#DefaultTimeZone =
# ----------------------------
# TCP Protocol Settings

View File

@ -4,7 +4,7 @@ Time zone support consists of `TIME WITH TIME ZONE` and `TIMESTAMP WITH TIME ZON
The first important thing to understand is that `TIME WITHOUT TIME ZONE`, `TIMESTAMP WITHOUT TIME ZONE` and `DATE` data types are defined to use the session time zone when converting from or to a `TIME WITH TIME ZONE` or `TIMESTAMP WITH TIME ZONE`. `TIME` and `TIMESTAMP` are synonymous to theirs respectively `WITHOUT TIME ZONE` data types.
The session time zone, as the name implies, can be a different one for each database attachment. It can be set with the isc_dpb_session_time_zone DPB, and if not, it starts by default defined to be the same time zone used by the Firebird database OS process.
The session time zone, as the name implies, can be a different one for each database attachment. It can be set with the isc_dpb_session_time_zone DPB, and if not, it starts by default defined to be the `firebird.conf` parameter `DefaultTimeZone` or the same time zone used by the Firebird OS process when the parameter is not defined. A change in `DefaultTimeZone` configuration or the OS time zone does not changes the default of a running Firebird process.
It can then be changed with `SET TIME ZONE` statement to a given time zone or reset to its original value with `SET TIME ZONE LOCAL`.

View File

@ -1836,6 +1836,12 @@ C --
PARAMETER (GDS__parameter_name = 335545211)
INTEGER*4 GDS__file_starting_page_err
PARAMETER (GDS__file_starting_page_err = 335545212)
INTEGER*4 GDS__invalid_timezone_offset
PARAMETER (GDS__invalid_timezone_offset = 335545213)
INTEGER*4 GDS__invalid_timezone_region
PARAMETER (GDS__invalid_timezone_region = 335545214)
INTEGER*4 GDS__invalid_timezone_id
PARAMETER (GDS__invalid_timezone_id = 335545215)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1831,6 +1831,12 @@ const
gds_parameter_name = 335545211;
isc_file_starting_page_err = 335545212;
gds_file_starting_page_err = 335545212;
isc_invalid_timezone_offset = 335545213;
gds_invalid_timezone_offset = 335545213;
isc_invalid_timezone_region = 335545214;
gds_invalid_timezone_region = 335545214;
isc_invalid_timezone_id = 335545215;
gds_invalid_timezone_id = 335545215;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -30,8 +30,10 @@
#include "firebird.h"
#include "../common/TimeZoneUtil.h"
#include "../common/StatusHolder.h"
#include "../common/classes/rwlock.h"
#include "../common/classes/timestamp.h"
#include "../common/classes/GenericMap.h"
#include "../common/config/config.h"
#include "unicode/ucal.h"
#ifdef TZ_UPDATE
@ -69,8 +71,7 @@ namespace
struct TimeZoneStartup
{
TimeZoneStartup(MemoryPool& pool)
: systemTimeZone(TimeZoneUtil::GMT_ZONE),
nameIdMap(pool)
: nameIdMap(pool)
{
#if defined DEV_BUILD && defined TZ_UPDATE
tzUpdate();
@ -82,55 +83,6 @@ namespace
s.upper();
nameIdMap.put(s, i);
}
UErrorCode icuErrorCode = U_ZERO_ERROR;
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(NULL, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
{
gds__log("ICU's ucal_open error opening the default callendar.");
return;
}
UChar buffer[TimeZoneUtil::MAX_SIZE];
bool found = false;
int32_t len = icuLib.ucalGetTimeZoneID(icuCalendar, buffer, FB_NELEM(buffer), &icuErrorCode);
if (!U_FAILURE(icuErrorCode))
{
bool error;
string bufferStrUnicode(reinterpret_cast<const char*>(buffer), len * sizeof(USHORT));
string bufferStrAscii(IntlUtil::convertUtf16ToAscii(bufferStrUnicode, &error));
found = getId(bufferStrAscii, systemTimeZone);
}
else
icuErrorCode = U_ZERO_ERROR;
if (found)
{
icuLib.ucalClose(icuCalendar);
return;
}
gds__log("ICU error retrieving the system time zone: %d. Fallbacking to displacement.", int(icuErrorCode));
int32_t displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
icuLib.ucalClose(icuCalendar);
if (!U_FAILURE(icuErrorCode))
{
int sign = displacement < 0 ? -1 : 1;
unsigned tzh = (unsigned) abs(int(displacement / 60));
unsigned tzm = (unsigned) abs(int(displacement % 60));
systemTimeZone = makeFromOffset(sign, tzh, tzm);
}
else
gds__log("Cannot retrieve the system time zone: %d.", int(icuErrorCode));
}
bool getId(string name, USHORT& id)
@ -225,8 +177,6 @@ namespace
}
#endif // defined DEV_BUILD && defined TZ_UPDATE
USHORT systemTimeZone;
private:
GenericMap<Pair<Left<string, USHORT> > > nameIdMap;
};
@ -242,7 +192,103 @@ static InitInstance<TimeZoneStartup> timeZoneStartup;
// Return the current user's time zone.
USHORT TimeZoneUtil::getSystemTimeZone()
{
return timeZoneStartup().systemTimeZone;
static volatile bool cachedError = false;
static volatile USHORT cachedTimeZoneId = TimeZoneUtil::GMT_ZONE;
static volatile int32_t cachedTimeZoneNameLen = -1;
static UChar cachedTimeZoneName[TimeZoneUtil::MAX_SIZE];
static GlobalPtr<RWLock> lock;
if (cachedError)
return cachedTimeZoneId;
// ASF: The code below in this function is prepared to detect changes in OS time zone or config setting, but
// the called functions are not. So cache and return directly the previously detected time zone.
if (cachedTimeZoneNameLen != -1)
return cachedTimeZoneId;
UErrorCode icuErrorCode = U_ZERO_ERROR;
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UChar buffer[TimeZoneUtil::MAX_SIZE];
int32_t len;
const char* configDefault = Config::getDefaultTimeZone();
if (configDefault && configDefault[0])
{
UChar* dst = buffer;
for (const char* src = configDefault; src - configDefault < TimeZoneUtil::MAX_SIZE && *src; ++src, ++dst)
*dst = *src;
*dst = 0;
len = dst - buffer;
}
else
len = icuLib.ucalGetDefaultTimeZone(buffer, FB_NELEM(buffer), &icuErrorCode);
ReadLockGuard readGuard(lock, "TimeZoneUtil::getSystemTimeZone");
if (!U_FAILURE(icuErrorCode) &&
cachedTimeZoneNameLen != -1 &&
len == cachedTimeZoneNameLen &&
memcmp(buffer, cachedTimeZoneName, len * sizeof(USHORT)) == 0)
{
return cachedTimeZoneId;
}
readGuard.release();
WriteLockGuard writeGuard(lock, "TimeZoneUtil::getSystemTimeZone");
string bufferStrAscii;
if (!U_FAILURE(icuErrorCode))
{
bool error;
string bufferStrUnicode(reinterpret_cast<const char*>(buffer), len * sizeof(USHORT));
bufferStrAscii = IntlUtil::convertUtf16ToAscii(bufferStrUnicode, &error);
USHORT id;
if (timeZoneStartup().getId(bufferStrAscii, id))
{
memcpy(cachedTimeZoneName, buffer, len * sizeof(USHORT));
cachedTimeZoneId = id;
cachedTimeZoneNameLen = len;
return cachedTimeZoneId;
}
}
else
icuErrorCode = U_ZERO_ERROR;
gds__log("ICU error (%d) retrieving the system time zone (%s). Falling back to displacement.",
int(icuErrorCode), bufferStrAscii.c_str());
UCalendar* icuCalendar = icuLib.ucalOpen(NULL, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
{
gds__log("ICU's ucal_open error opening the default callendar.");
cachedError = true;
return cachedTimeZoneId; // GMT
}
int32_t displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
icuLib.ucalClose(icuCalendar);
if (!U_FAILURE(icuErrorCode))
{
int sign = displacement < 0 ? -1 : 1;
unsigned tzh = (unsigned) abs(int(displacement / 60));
unsigned tzm = (unsigned) abs(int(displacement % 60));
cachedTimeZoneId = makeFromOffset(sign, tzh, tzm);
}
else
gds__log("Cannot retrieve the system time zone: %d.", int(icuErrorCode));
cachedError = true;
return cachedTimeZoneId;
}
void TimeZoneUtil::getDatabaseVersion(Firebird::string& str)
@ -299,7 +345,7 @@ USHORT TimeZoneUtil::parse(const char* str, unsigned strLen)
}
if (p != end)
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone offset"); //// TODO:
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << string(str, strLen));
return makeFromOffset(sign, tzh, tzm);
}
@ -341,7 +387,7 @@ USHORT TimeZoneUtil::parseRegion(const char* str, unsigned strLen)
return id;
}
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone region"); //// TODO:
status_exception::raise(Arg::Gds(isc_invalid_timezone_region) << string(start, len));
return 0;
}
@ -383,7 +429,9 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
{
SSHORT displacement;
if (isOffset(timeStampTz.time_zone))
if (timeStampTz.time_zone == GMT_ZONE)
displacement = 0;
else if (isOffset(timeStampTz.time_zone))
displacement = offsetZoneToDisplacement(timeStampTz.time_zone);
else
{
@ -470,7 +518,7 @@ void TimeZoneUtil::localTimeToUtc(ISC_TIME& time, Callbacks* cb)
void TimeZoneUtil::localTimeToUtc(ISC_TIME_TZ& timeTz, Callbacks* cb)
{
ISC_TIMESTAMP_TZ tempTimeStampTz;
tempTimeStampTz.utc_timestamp.timestamp_date = cb->getCurrentTimeStampUtc().timestamp_date;
tempTimeStampTz.utc_timestamp.timestamp_date = cb->getCurrentGmtTimeStamp().timestamp_date;
tempTimeStampTz.utc_timestamp.timestamp_time = timeTz.utc_time;
tempTimeStampTz.time_zone = timeTz.time_zone;
localTimeStampToUtc(tempTimeStampTz);
@ -497,7 +545,9 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
{
int displacement;
if (isOffset(timeStampTz.time_zone))
if (timeStampTz.time_zone == GMT_ZONE)
return;
else if (isOffset(timeStampTz.time_zone))
displacement = offsetZoneToDisplacement(timeStampTz.time_zone);
else
{
@ -554,7 +604,9 @@ void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct t
timeStampTz.utc_timestamp.timestamp_time;
int displacement;
if (isOffset(timeStampTz.time_zone))
if (timeStampTz.time_zone == GMT_ZONE)
displacement = 0;
else if (isOffset(timeStampTz.time_zone))
displacement = offsetZoneToDisplacement(timeStampTz.time_zone);
else
{
@ -597,7 +649,7 @@ void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct t
TimeStamp::decode_timestamp(ts, times, fractions);
}
ISC_TIMESTAMP_TZ TimeZoneUtil::getCurrentTimeStampUtc()
ISC_TIMESTAMP_TZ TimeZoneUtil::getCurrentSystemTimeStamp()
{
TimeStamp now = TimeStamp::getCurrentTimeStamp();
@ -609,10 +661,82 @@ ISC_TIMESTAMP_TZ TimeZoneUtil::getCurrentTimeStampUtc()
return tsTz;
}
void TimeZoneUtil::validateTimeStampUtc(NoThrowTimeStamp& ts)
ISC_TIMESTAMP_TZ TimeZoneUtil::getCurrentGmtTimeStamp()
{
NoThrowTimeStamp now;
// ASF: This comment is copied from NoThrowTimeStamp::getCurrentTimeStamp.
// NS: We round generated timestamps to whole millisecond.
// Not many applications can deal with fractional milliseconds properly and
// we do not use high resolution timers either so actual time granularity
// is going to to be somewhere in range between 1 ms (like on UNIX/Risc)
// and 53 ms (such as Win9X)
int milliseconds;
#ifdef WIN_NT
SYSTEMTIME stUtc;
GetSystemTime(&stUtc);
milliseconds = stUtc.wMilliseconds;
#else
time_t seconds; // UTC time
#ifdef HAVE_GETTIMEOFDAY
struct timeval tp;
GETTIMEOFDAY(&tp);
seconds = tp.tv_sec;
milliseconds = tp.tv_usec / 1000;
#else
struct timeb time_buffer;
ftime(&time_buffer);
seconds = time_buffer.time;
milliseconds = time_buffer.millitm;
#endif
#endif // WIN_NT
const int fractions = milliseconds * ISC_TIME_SECONDS_PRECISION / 1000;
#ifdef WIN_NT
// Manually convert SYSTEMTIME to "struct tm" used below
struct tm times, *ptimes = &times;
times.tm_sec = stUtc.wSecond; // seconds after the minute - [0,59]
times.tm_min = stUtc.wMinute; // minutes after the hour - [0,59]
times.tm_hour = stUtc.wHour; // hours since midnight - [0,23]
times.tm_mday = stUtc.wDay; // day of the month - [1,31]
times.tm_mon = stUtc.wMonth - 1; // months since January - [0,11]
times.tm_year = stUtc.wYear - 1900; // years since 1900
times.tm_wday = stUtc.wDayOfWeek; // days since Sunday - [0,6]
// --- no used for encoding below
times.tm_yday = 0; // days since January 1 - [0,365]
times.tm_isdst = -1; // daylight savings time flag
#else
#ifdef HAVE_GMTIME_R
struct tm times, *ptimes = &times;
if (!gmtime_r(&seconds, &times))
system_call_failed::raise("gmtime_r");
#else
struct tm *ptimes = gmtime(&seconds);
if (!ptimes)
system_call_failed::raise("gmtime");
#endif
#endif // WIN_NT
now.encode(ptimes, fractions);
ISC_TIMESTAMP_TZ tsTz;
tsTz.utc_timestamp = now.value();
tsTz.time_zone = GMT_ZONE;
return tsTz;
}
void TimeZoneUtil::validateGmtTimeStamp(NoThrowTimeStamp& ts)
{
if (ts.isEmpty())
ts.value() = getCurrentTimeStampUtc().utc_timestamp;
ts.value() = getCurrentGmtTimeStamp().utc_timestamp;
}
// Converts a time to timestamp-tz.
@ -834,7 +958,7 @@ static const TimeZoneDesc* getDesc(USHORT timeZone)
if (MAX_USHORT - timeZone < FB_NELEM(TIME_ZONE_LIST))
return &TIME_ZONE_LIST[MAX_USHORT - timeZone];
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone id"); //// TODO:
status_exception::raise(Arg::Gds(isc_invalid_timezone_id) << Arg::Num(timeZone));
return nullptr;
}
@ -848,7 +972,11 @@ static inline bool isOffset(USHORT timeZone)
static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm)
{
if (!TimeZoneUtil::isValidOffset(sign, tzh, tzm))
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone offset"); //// TODO:
{
string str;
str.printf("%s%02u:%02u", (sign == -1 ? "-" : "+"), tzh, tzm);
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << str);
}
return (USHORT)((tzh * 60 + tzm) * sign + ONE_DAY);
}
@ -871,7 +999,7 @@ static int parseNumber(const char*& p, const char* end)
n = n * 10 + *p++ - '0';
if (p == start)
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone offset"); //// TODO:
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << string(start, end - start));
return n;
}

View File

@ -102,9 +102,10 @@ public:
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 ISC_TIMESTAMP_TZ getCurrentTimeStampUtc();
static ISC_TIMESTAMP_TZ getCurrentSystemTimeStamp();
static ISC_TIMESTAMP_TZ getCurrentGmtTimeStamp();
static void validateTimeStampUtc(NoThrowTimeStamp& ts);
static void validateGmtTimeStamp(NoThrowTimeStamp& ts);
static ISC_TIMESTAMP_TZ cvtTimeToTimeStampTz(const ISC_TIME& time, Callbacks* cb);
static ISC_TIME_TZ cvtTimeToTimeTz(const ISC_TIME& time, Callbacks* cb);

View File

@ -151,6 +151,7 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_INTEGER, "DefaultDbCachePages", (ConfigValue) -1}, // pages
{TYPE_INTEGER, "ConnectionTimeout", (ConfigValue) 180}, // seconds
{TYPE_INTEGER, "DummyPacketInterval", (ConfigValue) 0}, // seconds
{TYPE_STRING, "DefaultTimeZone", (ConfigValue) ""},
{TYPE_INTEGER, "LockMemSize", (ConfigValue) 1048576}, // bytes
{TYPE_INTEGER, "LockHashSlots", (ConfigValue) 8191}, // slots
{TYPE_INTEGER, "LockAcquireSpins", (ConfigValue) 0},
@ -517,6 +518,11 @@ int Config::getDummyPacketInterval() const
return get<int>(KEY_DUMMY_PACKET_INTERVAL);
}
const char* Config::getDefaultTimeZone()
{
return getDefaultConfig()->get<const char*>(KEY_DEFAULT_TIME_ZONE);
}
int Config::getLockMemSize() const
{
int size = get<int>(KEY_LOCK_MEM_SIZE);

View File

@ -98,6 +98,7 @@ public:
KEY_DEFAULT_DB_CACHE_PAGES,
KEY_CONNECTION_TIMEOUT,
KEY_DUMMY_PACKET_INTERVAL,
KEY_DEFAULT_TIME_ZONE,
KEY_LOCK_MEM_SIZE,
KEY_LOCK_HASH_SLOTS,
KEY_LOCK_ACQUIRE_SPINS,
@ -263,6 +264,8 @@ public:
// Dummy packet interval
int getDummyPacketInterval() const;
static const char* getDefaultTimeZone();
// Lock manager memory size
int getLockMemSize() const;

View File

@ -3417,7 +3417,7 @@ namespace
virtual void validateLength(Jrd::CharSet* toCharset, SLONG toLength, const UCHAR* start,
const USHORT to_size);
virtual SLONG getLocalDate();
virtual ISC_TIMESTAMP getCurrentTimeStampUtc();
virtual ISC_TIMESTAMP getCurrentGmtTimeStamp();
virtual USHORT getSessionTimeZone();
virtual void isVersion4(bool& v4);
} commonCallbacks(status_exception::raise);
@ -3451,9 +3451,9 @@ namespace
return TimeStamp::getCurrentTimeStamp().value().timestamp_date;
}
ISC_TIMESTAMP CommonCallbacks::getCurrentTimeStampUtc()
ISC_TIMESTAMP CommonCallbacks::getCurrentGmtTimeStamp()
{
return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentTimeStampUtc(), TimeZoneUtil::GMT_ZONE);
return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentSystemTimeStamp(), TimeZoneUtil::GMT_ZONE);
}
USHORT CommonCallbacks::getSessionTimeZone()

View File

@ -61,7 +61,7 @@ public:
virtual void validateLength(Jrd::CharSet* toCharset, SLONG toLength, const UCHAR* start,
const USHORT to_size) = 0;
virtual SLONG getLocalDate() = 0;
virtual ISC_TIMESTAMP getCurrentTimeStampUtc() = 0;
virtual ISC_TIMESTAMP getCurrentGmtTimeStamp() = 0;
virtual USHORT getSessionTimeZone() = 0;
virtual void isVersion4(bool& v4) = 0;

View File

@ -285,6 +285,7 @@ private:
return;
getEntryPoint("ucal_getTZDataVersion", inModule, ucalGetTZDataVersion);
getEntryPoint("ucal_getDefaultTimeZone", inModule, ucalGetDefaultTimeZone);
getEntryPoint("ucal_open", inModule, ucalOpen);
getEntryPoint("ucal_close", inModule, ucalClose);
getEntryPoint("ucal_setMillis", inModule, ucalSetMillis);

View File

@ -124,6 +124,7 @@ public:
int32_t (U_EXPORT2* ustrcmp) (const UChar* s1, const UChar* s2);
const char* (U_EXPORT2* ucalGetTZDataVersion) (UErrorCode* status);
int32_t (U_EXPORT2* ucalGetDefaultTimeZone) (UChar* result, int32_t resultCapacity, UErrorCode* ec);
UCalendar* (U_EXPORT2* ucalOpen) (const UChar* zoneID, int32_t len, const char* locale, UCalendarType type,
UErrorCode* err);
void (U_EXPORT2* ucalClose) (UCalendar* cal);

View File

@ -4124,10 +4124,10 @@ dsc* CurrentDateNode::execute(thread_db* tdbb, jrd_req* request) const
request->req_flags &= ~req_null;
// Use the request timestamp.
fb_assert(!request->req_timestamp_utc.isEmpty());
fb_assert(!request->req_gmt_timestamp.isEmpty());
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.utc_timestamp = request->req_timestamp_utc.value();
timeStampTz.utc_timestamp = request->req_gmt_timestamp.value();
timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE;
impure->vlu_misc.vlu_sql_date = TimeZoneUtil::timeStampTzToTimeStamp(
@ -4238,9 +4238,9 @@ dsc* CurrentTimeNode::execute(thread_db* tdbb, jrd_req* request) const
request->req_flags &= ~req_null;
// Use the request timestamp.
fb_assert(!request->req_timestamp_utc.isEmpty());
fb_assert(!request->req_gmt_timestamp.isEmpty());
ISC_TIME time = request->req_timestamp_utc.value().timestamp_time;
ISC_TIME time = request->req_gmt_timestamp.value().timestamp_time;
TimeStamp::round_time(time, precision);
impure->vlu_desc.dsc_dtype = dtype_sql_time_tz;
@ -4351,8 +4351,8 @@ dsc* CurrentTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const
request->req_flags &= ~req_null;
// Use the request timestamp.
fb_assert(!request->req_timestamp_utc.isEmpty());
ISC_TIMESTAMP encTimes = request->req_timestamp_utc.value();
fb_assert(!request->req_gmt_timestamp.isEmpty());
ISC_TIMESTAMP encTimes = request->req_gmt_timestamp.value();
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp_tz;
@ -7943,10 +7943,10 @@ dsc* LocalTimeNode::execute(thread_db* tdbb, jrd_req* request) const
request->req_flags &= ~req_null;
// Use the request timestamp.
fb_assert(!request->req_timestamp_utc.isEmpty());
fb_assert(!request->req_gmt_timestamp.isEmpty());
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.utc_timestamp = request->req_timestamp_utc.value();
timeStampTz.utc_timestamp = request->req_gmt_timestamp.value();
timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE;
impure->vlu_misc.vlu_sql_time = TimeZoneUtil::timeStampTzToTimeStamp(
@ -8046,7 +8046,7 @@ dsc* LocalTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const
request->req_flags &= ~req_null;
// Use the request timestamp.
fb_assert(!request->req_timestamp_utc.isEmpty());
fb_assert(!request->req_gmt_timestamp.isEmpty());
impure->vlu_misc.vlu_timestamp = request->getLocalTimeStamp().value();
TimeStamp::round_time(impure->vlu_misc.vlu_timestamp.timestamp_time, precision);
@ -12807,7 +12807,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
{
Jrd::ContextPoolHolder context(tdbb, funcRequest->req_pool); // Save the old pool.
funcRequest->req_timestamp_utc = request->req_timestamp_utc;
funcRequest->req_gmt_timestamp = request->req_gmt_timestamp;
EXE_start(tdbb, funcRequest, transaction);
@ -12836,7 +12836,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
EXE_unwind(tdbb, funcRequest);
funcRequest->req_attachment = NULL;
funcRequest->req_flags &= ~(req_in_use | req_proc_fetch);
funcRequest->req_timestamp_utc.invalidate();
funcRequest->req_gmt_timestamp.invalidate();
throw;
}
@ -12864,7 +12864,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
funcRequest->req_attachment = NULL;
funcRequest->req_flags &= ~(req_in_use | req_proc_fetch);
funcRequest->req_timestamp_utc.invalidate();
funcRequest->req_gmt_timestamp.invalidate();
}
if (!(request->req_flags & req_null))

View File

@ -3188,7 +3188,7 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
try
{
procRequest->req_timestamp_utc = request->req_timestamp_utc;
procRequest->req_gmt_timestamp = request->req_gmt_timestamp;
EXE_start(tdbb, procRequest, transaction);

View File

@ -914,6 +914,9 @@ static const struct {
{"plugin_name", 335545210},
{"parameter_name", 335545211},
{"file_starting_page_err", 335545212},
{"invalid_timezone_offset", 335545213},
{"invalid_timezone_region", 335545214},
{"invalid_timezone_id", 335545215},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -948,6 +948,9 @@ const ISC_STATUS isc_ses_reset_tran_rollback = 335545209L;
const ISC_STATUS isc_plugin_name = 335545210L;
const ISC_STATUS isc_parameter_name = 335545211L;
const ISC_STATUS isc_file_starting_page_err = 335545212L;
const ISC_STATUS isc_invalid_timezone_offset = 335545213L;
const ISC_STATUS isc_invalid_timezone_region = 335545214L;
const ISC_STATUS isc_invalid_timezone_id = 335545215L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1422,7 +1425,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1366;
const ISC_STATUS isc_err_max = 1369;
#else /* c definitions */
@ -2340,6 +2343,9 @@ const ISC_STATUS isc_err_max = 1366;
#define isc_plugin_name 335545210L
#define isc_parameter_name 335545211L
#define isc_file_starting_page_err 335545212L
#define isc_invalid_timezone_offset 335545213L
#define isc_invalid_timezone_region 335545214L
#define isc_invalid_timezone_id 335545215L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2814,7 +2820,7 @@ const ISC_STATUS isc_err_max = 1366;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1366
#define isc_err_max 1369
#endif

View File

@ -917,6 +917,9 @@ 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 */
{335545214, "Invalid time zone region: @1"}, /* invalid_timezone_region */
{335545215, "Invalid time zone ID: @1"}, /* invalid_timezone_id */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -913,6 +913,9 @@ static const struct {
{335545210, -901}, /* 890 plugin_name */
{335545211, -901}, /* 891 parameter_name */
{335545212, -901}, /* 892 file_starting_page_err */
{335545213, -901}, /* 893 invalid_timezone_offset */
{335545214, -901}, /* 894 invalid_timezone_region */
{335545215, -901}, /* 895 invalid_timezone_id */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -913,6 +913,9 @@ static const struct {
{335545210, "00000"}, // 890 plugin_name
{335545211, "42000"}, // 891 parameter_name
{335545212, "HY000"}, // 892 file_starting_page_err
{335545213, "22009"}, // 893 invalid_timezone_offset
{335545214, "22009"}, // 894 invalid_timezone_region
{335545215, "22009"}, // 895 invalid_timezone_id
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -212,7 +212,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_base_stats(*pool),
att_working_directory(*pool),
att_filename(*pool),
att_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
att_timestamp(TimeZoneUtil::getCurrentSystemTimeStamp()),
att_context_vars(*pool),
ddlTriggersContext(*pool),
att_network_protocol(*pool),
@ -952,20 +952,19 @@ void Attachment::setupIdleTimer(bool clear)
}
}
bool Attachment::getIdleTimerTimestamp(TimeStamp& ts) const
bool Attachment::getIdleTimerTimestamp(ISC_TIMESTAMP_TZ& ts) const
{
if (!att_idle_timer)
return false;
time_t value = att_idle_timer->getExpiryTime();
SINT64 value = att_idle_timer->getExpiryTime();
if (!value)
return false;
struct tm* times = localtime(&value);
if (!times)
return false;
ts.utc_timestamp.timestamp_date = value / TimeStamp::ISC_TICKS_PER_DAY;
ts.utc_timestamp.timestamp_time = value % TimeStamp::ISC_TICKS_PER_DAY;
ts.time_zone = TimeZoneUtil::GMT_ZONE;
ts = TimeStamp::encode_timestamp(times);
return true;
}
@ -991,10 +990,14 @@ void Attachment::IdleTimer::handler()
return;
// If timer was reset to fire later, restart ITimer
time_t curTime = time(NULL);
if (curTime < m_expTime)
const ISC_TIMESTAMP currentTimeGmt = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
const SINT64 curTime = currentTimeGmt.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
(SINT64) currentTimeGmt.timestamp_time;
if (curTime + ISC_TIME_SECONDS_PRECISION < m_expTime)
{
reset(m_expTime - curTime);
reset((m_expTime - curTime) / ISC_TIME_SECONDS_PRECISION);
return;
}
@ -1018,6 +1021,8 @@ void Attachment::IdleTimer::reset(unsigned int timeout)
{
// Start timer if necessary. If timer was already started, don't restart
// (or stop) it - handler() will take care about it.
// Take into account that timeout is in seconds while m_expTime is in ISC ticks
// and ITimerControl works with microseconds.
if (!timeout)
{
@ -1025,8 +1030,11 @@ void Attachment::IdleTimer::reset(unsigned int timeout)
return;
}
const time_t curTime = time(NULL);
m_expTime = curTime + timeout;
const ISC_TIMESTAMP currentTimeGmt = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
const SINT64 curTime = currentTimeGmt.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
(SINT64) currentTimeGmt.timestamp_time;
m_expTime = curTime + timeout * ISC_TIME_SECONDS_PRECISION;
FbLocalStatus s;
ITimerControl* timerCtrl = Firebird::TimerInterfacePtr();
@ -1041,7 +1049,8 @@ void Attachment::IdleTimer::reset(unsigned int timeout)
m_fireTime = 0;
}
timerCtrl->start(&s, this, (m_expTime - curTime) * 1000 * 1000);
// Convert ISC ticks into microseconds
timerCtrl->start(&s, this, (m_expTime - curTime) * (1000 * 1000 / ISC_TIME_SECONDS_PRECISION));
check(&s);
m_fireTime = m_expTime;
}

View File

@ -336,7 +336,7 @@ public:
Validation* att_validation;
Firebird::PathName att_working_directory; // Current working directory is cached
Firebird::PathName att_filename; // alias used to attach the database
const Firebird::TimeStamp att_timestamp; // Connection date and time
const ISC_TIMESTAMP_TZ att_timestamp; // Connection date and time
Firebird::StringMap att_context_vars; // Context variables for the connection
Firebird::Stack<DdlTriggerContext*> ddlTriggersContext; // Context variables for DDL trigger event
Firebird::string att_network_protocol; // Network protocol used by client for connection
@ -488,7 +488,7 @@ public:
void setupIdleTimer(bool clear);
// returns time when idle timer will be expired, if set
bool getIdleTimerTimestamp(Firebird::TimeStamp& ts) const;
bool getIdleTimerTimestamp(ISC_TIMESTAMP_TZ& ts) const;
// batches control
void registerBatch(JBatch* b)
@ -522,15 +522,15 @@ private:
// Set timeout, seconds
void reset(unsigned int timeout);
time_t getExpiryTime() const
SINT64 getExpiryTime() const
{
return m_expTime;
}
private:
Firebird::RefPtr<JAttachment> m_attachment;
time_t m_fireTime; // when ITimer will fire, could be less than m_expTime
time_t m_expTime; // when actual idle timeout will expire
SINT64 m_fireTime; // when ITimer will fire, could be less than m_expTime
SINT64 m_expTime; // when actual idle timeout will expire
};
unsigned int att_idle_timeout; // seconds

View File

@ -424,7 +424,7 @@ public:
TipCache* dbb_tip_cache; // cache of latest known state of all transactions in system
BackupManager* dbb_backup_manager; // physical backup manager
Firebird::TimeStamp dbb_creation_date; // creation date
ISC_TIMESTAMP_TZ dbb_creation_date; // creation timestamp in GMT
ExternalFileDirectoryList* dbb_external_file_directory_list;
Firebird::RefPtr<const Config> dbb_config;
@ -481,7 +481,7 @@ private:
dbb_stats(*p),
dbb_lock_owner_id(getLockOwnerId()),
dbb_tip_cache(NULL),
dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()),
dbb_creation_date(Firebird::TimeZoneUtil::getCurrentGmtTimeStamp()),
dbb_external_file_directory_list(NULL),
dbb_init_fini(FB_NEW_POOL(*getDefaultMemoryPool()) ExistenceRefMutex()),
dbb_linger_seconds(0),

View File

@ -821,7 +821,7 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record)
temp = (database->dbb_flags & DBB_no_reserve) ? 0 : 1;
record.storeInteger(f_mon_db_res_space, temp);
// creation date
record.storeTimestamp(f_mon_db_created, database->dbb_creation_date);
record.storeTimestampTz(f_mon_db_created, database->dbb_creation_date);
// database size
record.storeInteger(f_mon_db_pages, PageSpace::actAlloc(database));
// database backup state
@ -925,7 +925,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
// charset
record.storeInteger(f_mon_att_charset_id, attachment->att_charset);
// timestamp
record.storeTimestamp(f_mon_att_timestamp, attachment->att_timestamp);
record.storeTimestampTz(f_mon_att_timestamp, attachment->att_timestamp);
// garbage collection flag
temp = (attachment->att_flags & ATT_no_cleanup) ? 0 : 1;
record.storeInteger(f_mon_att_gc, temp);
@ -949,9 +949,9 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
// session idle timeout, seconds
record.storeInteger(f_mon_att_idle_timeout, attachment->getIdleTimeout());
// when idle timer expires, NULL if not running
TimeStamp idleTimer;
ISC_TIMESTAMP_TZ idleTimer;
if (attachment->getIdleTimerTimestamp(idleTimer))
record.storeTimestamp(f_mon_att_idle_timer, idleTimer);
record.storeTimestampTz(f_mon_att_idle_timer, idleTimer);
// statement timeout, milliseconds
record.storeInteger(f_mon_att_stmt_timeout, attachment->getStatementTimeout());
@ -990,7 +990,7 @@ void Monitoring::putTransaction(SnapshotData::DumpRecord& record, const jrd_tra*
temp = transaction->tra_requests ? mon_state_active : mon_state_idle;
record.storeInteger(f_mon_tra_state, temp);
// timestamp
record.storeTimestamp(f_mon_tra_timestamp, transaction->tra_timestamp);
record.storeTimestampTz(f_mon_tra_timestamp, transaction->tra_timestamp);
// top transaction
record.storeInteger(f_mon_tra_top, transaction->tra_top);
// oldest transaction
@ -1053,13 +1053,13 @@ void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* req
const bool is_stalled = (request->req_flags & req_stall);
record.storeInteger(f_mon_stmt_state, is_stalled ? mon_state_stalled : mon_state_active);
record.storeInteger(f_mon_stmt_tra_id, request->req_transaction->tra_number);
record.storeTimestamp(f_mon_stmt_timestamp, request->getLocalTimeStamp().value());
record.storeTimestampTz(f_mon_stmt_timestamp, request->getTimeStampTz());
ISC_TIMESTAMP ts;
ISC_TIMESTAMP_TZ ts;
if (request->req_timer &&
request->req_timer->getExpireTimestamp(request->getLocalTimeStamp().value(), ts))
request->req_timer->getExpireTimestamp(request->getTimeStampTz(), ts))
{
record.storeTimestamp(f_mon_stmt_timer, ts);
record.storeTimestampTz(f_mon_stmt_timer, ts);
}
}
else
@ -1133,7 +1133,7 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const jrd_req* reques
}
// timestamp
record.storeTimestamp(f_mon_call_timestamp, request->getLocalTimeStamp().value());
record.storeTimestampTz(f_mon_call_timestamp, request->getTimeStampTz());
// source line/column
if (request->req_src_line)
{

View File

@ -145,7 +145,7 @@ public:
void storeTimestampTz(int field_id, const ISC_TIMESTAMP_TZ& value)
{
storeField(field_id, VALUE_TIMESTAMP_TZ, sizeof(ISC_TIMESTAMP), &value);
storeField(field_id, VALUE_TIMESTAMP_TZ, sizeof(ISC_TIMESTAMP_TZ), &value);
}
void storeString(int field_id, const Firebird::string& value)

View File

@ -571,9 +571,9 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool&
Jrd::ContextPoolHolder context(tdbb, expr_request->req_pool);
if (org_request)
expr_request->req_timestamp_utc = org_request->req_timestamp_utc;
expr_request->req_gmt_timestamp = org_request->req_gmt_timestamp;
else
TimeZoneUtil::validateTimeStampUtc(expr_request->req_timestamp_utc);
TimeZoneUtil::validateGmtTimeStamp(expr_request->req_gmt_timestamp);
if (!(result = EVL_expr(tdbb, expr_request, idx->idx_expression)))
result = &idx->idx_expression_desc;
@ -587,7 +587,7 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool&
expr_request->req_caller = NULL;
expr_request->req_flags &= ~req_in_use;
expr_request->req_timestamp_utc.invalidate();
expr_request->req_gmt_timestamp.invalidate();
throw;
}
@ -597,7 +597,7 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool&
expr_request->req_caller = NULL;
expr_request->req_flags &= ~req_in_use;
expr_request->req_timestamp_utc.invalidate();
expr_request->req_gmt_timestamp.invalidate();
return result;
}

View File

@ -513,26 +513,26 @@ SLONG EngineCallbacks::getLocalDate()
if (tdbb && (tdbb->getType() == ThreadData::tddDBB) && tdbb->getRequest())
{
fb_assert(!tdbb->getRequest()->req_timestamp_utc.isEmpty());
fb_assert(!tdbb->getRequest()->req_gmt_timestamp.isEmpty());
return tdbb->getRequest()->getLocalTimeStamp().value().timestamp_date;
}
return TimeZoneUtil::timeStampTzToTimeStamp(
TimeZoneUtil::getCurrentTimeStampUtc(), getSessionTimeZone()).timestamp_date;
TimeZoneUtil::getCurrentSystemTimeStamp(), getSessionTimeZone()).timestamp_date;
}
ISC_TIMESTAMP EngineCallbacks::getCurrentTimeStampUtc()
ISC_TIMESTAMP EngineCallbacks::getCurrentGmtTimeStamp()
{
thread_db* tdbb = JRD_get_thread_data();
if (tdbb && (tdbb->getType() == ThreadData::tddDBB) && tdbb->getRequest())
{
fb_assert(!tdbb->getRequest()->req_timestamp_utc.isEmpty());
return tdbb->getRequest()->req_timestamp_utc.value();
fb_assert(!tdbb->getRequest()->req_gmt_timestamp.isEmpty());
return tdbb->getRequest()->req_gmt_timestamp.value();
}
return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentTimeStampUtc(), TimeZoneUtil::GMT_ZONE);
return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentSystemTimeStamp(), TimeZoneUtil::GMT_ZONE);
}

View File

@ -60,7 +60,7 @@ namespace Jrd
virtual void validateLength(CharSet* toCharset, SLONG toLength, const UCHAR* start,
const USHORT to_size);
virtual SLONG getLocalDate();
virtual ISC_TIMESTAMP getCurrentTimeStampUtc();
virtual ISC_TIMESTAMP getCurrentGmtTimeStamp();
virtual USHORT getSessionTimeZone();
virtual void isVersion4(bool& v4);

View File

@ -5888,7 +5888,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
AutoSetRestore2<jrd_req*, thread_db> autoRequest(tdbb,
&thread_db::getRequest, &thread_db::setRequest, defaultRequest);
TimeZoneUtil::validateTimeStampUtc(defaultRequest->req_timestamp_utc);
TimeZoneUtil::validateGmtTimeStamp(defaultRequest->req_gmt_timestamp);
TRA_attach_request(transaction, defaultRequest);
dsc* result = EVL_expr(tdbb, defaultRequest, defaultNode);

View File

@ -890,7 +890,7 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction)
request->req_records_affected.clear();
// Store request start time for timestamp work
TimeZoneUtil::validateTimeStampUtc(request->req_timestamp_utc);
TimeZoneUtil::validateGmtTimeStamp(request->req_gmt_timestamp);
// Set all invariants to not computed.
const ULONG* const* ptr, * const* end;
@ -983,7 +983,7 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
request->req_flags &= ~(req_active | req_proc_fetch | req_reserved);
request->req_flags |= req_abort | req_stall;
request->req_timestamp_utc.invalidate();
request->req_gmt_timestamp.invalidate();
request->req_caller = NULL;
request->req_proc_inputs = NULL;
request->req_proc_caller = NULL;
@ -1106,9 +1106,9 @@ void EXE_execute_triggers(thread_db* tdbb,
TimeStamp timestamp;
if (request)
timestamp = request->req_timestamp_utc;
timestamp = request->req_gmt_timestamp;
else
TimeZoneUtil::validateTimeStampUtc(timestamp);
TimeZoneUtil::validateGmtTimeStamp(timestamp);
jrd_req* trigger = NULL;
@ -1154,7 +1154,7 @@ void EXE_execute_triggers(thread_db* tdbb,
}
}
trigger->req_timestamp_utc = timestamp;
trigger->req_gmt_timestamp = timestamp;
trigger->req_trigger_action = trigger_action;
TraceTrigExecute trace(tdbb, trigger, which_trig);
@ -1378,7 +1378,7 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
TRA_release_request_snapshot(tdbb, request);
request->req_flags &= ~(req_active | req_reserved);
request->req_timestamp_utc.invalidate();
request->req_gmt_timestamp.invalidate();
release_blobs(tdbb, request);
}

View File

@ -51,6 +51,7 @@
#include "../dsql/StmtNodes.h"
#include "../jrd/license.h"
#include "../jrd/cch_proto.h"
#include "../jrd/cvt_proto.h"
#include "../jrd/inf_proto.h"
#include "../common/isc_proto.h"
#include "../jrd/opt_proto.h"
@ -487,13 +488,23 @@ void INF_database_info(thread_db* tdbb,
case isc_info_creation_date:
{
const ISC_TIMESTAMP ts = dbb->dbb_creation_date.value();
const ISC_TIMESTAMP ts = TimeZoneUtil::cvtTimeStampTzToTimeStamp(
dbb->dbb_creation_date, &EngineCallbacks::instance);
length = INF_convert(ts.timestamp_date, p);
p += length;
length += INF_convert(ts.timestamp_time, p);
}
break;
case fb_info_creation_timestamp_tz:
length = INF_convert(dbb->dbb_creation_date.utc_timestamp.timestamp_date, p);
p += length;
length += INF_convert(dbb->dbb_creation_date.utc_timestamp.timestamp_time, p);
p += length;
length += INF_convert(dbb->dbb_creation_date.time_zone, p);
break;
case isc_info_no_reserve:
*p++ = (dbb->dbb_flags & DBB_no_reserve) ? 1 : 0;
length = p - buffer;

View File

@ -158,6 +158,8 @@ enum db_info_types
fb_info_protocol_version = 137,
fb_info_crypt_plugin = 138,
fb_info_creation_timestamp_tz = 139,
isc_info_db_last_value /* Leave this LAST! */
};

View File

@ -8184,18 +8184,18 @@ unsigned int TimeoutTimer::timeToExpire() const
return r > 0 ? r : 0;
}
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const
{
if (!m_started || m_expired)
return false;
static const SINT64 ISC_TICKS_PER_DAY = 24 * 60 * 60 * ISC_TIME_SECONDS_PRECISION;
SINT64 ticks = start.timestamp_date * ISC_TICKS_PER_DAY + start.timestamp_time;
SINT64 ticks = start.utc_timestamp.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
start.utc_timestamp.timestamp_time;
ticks += m_value * ISC_TIME_SECONDS_PRECISION / 1000;
exp.timestamp_date = ticks / ISC_TICKS_PER_DAY;
exp.timestamp_time = ticks % ISC_TICKS_PER_DAY;
exp.utc_timestamp.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY;
exp.utc_timestamp.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
exp.time_zone = start.time_zone;
return true;
}
@ -8256,18 +8256,18 @@ unsigned int TimeoutTimer::timeToExpire() const
return r > 0 ? r : 0;
}
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const
{
if (!m_start)
return false;
static const SINT64 ISC_TICKS_PER_DAY = 24 * 60 * 60 * ISC_TIME_SECONDS_PRECISION;
SINT64 ticks = start.timestamp_date * ISC_TICKS_PER_DAY + start.timestamp_time;
SINT64 ticks = start.utc_timestamp.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
start.utc_timestamp.timestamp_time;
ticks += m_value * ISC_TIME_SECONDS_PRECISION / 1000;
exp.timestamp_date = ticks / ISC_TICKS_PER_DAY;
exp.timestamp_time = ticks % ISC_TICKS_PER_DAY;
exp.utc_timestamp.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY;
exp.utc_timestamp.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
exp.time_zone = start.time_zone;
return true;
}

View File

@ -385,7 +385,7 @@ public:
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const;
bool getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
@ -429,7 +429,7 @@ public:
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const;
bool getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)

View File

@ -281,7 +281,7 @@ USHORT PAG_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start)
#ifdef SUPPORT_RAW_DEVICES
// The following lines (taken from PAG_format_header) are needed to identify
// this file in raw_devices_validate_database as a valid database attachment.
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeStamp::getCurrentTimeStamp().value();
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
// should we include milliseconds or not?
//TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
@ -953,7 +953,7 @@ void PAG_format_header(thread_db* tdbb)
WIN window(HEADER_PAGE_NUMBER);
header_page* header = (header_page*) CCH_fake(tdbb, &window, 1);
header->hdr_header.pag_scn = 0;
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeStamp::getCurrentTimeStamp().value();
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
// should we include milliseconds or not?
//TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
header->hdr_header.pag_type = pag_header;
@ -1150,7 +1150,8 @@ void PAG_header(thread_db* tdbb, bool info)
dbb->dbb_oldest_snapshot = oldest_snapshot;
dbb->dbb_attachment_id = header->hdr_attachment_id;
dbb->dbb_creation_date = *(ISC_TIMESTAMP*) header->hdr_creation_date;
dbb->dbb_creation_date.utc_timestamp = *(ISC_TIMESTAMP*) header->hdr_creation_date;
dbb->dbb_creation_date.time_zone = TimeZoneUtil::GMT_ZONE;
if (header->hdr_flags & hdr_read_only)
{

View File

@ -106,7 +106,7 @@ void ProcedureScan::open(thread_db* tdbb) const
try
{
proc_request->req_timestamp_utc = request->req_timestamp_utc;
proc_request->req_gmt_timestamp = request->req_gmt_timestamp;
TraceProcExecute trace(tdbb, proc_request, request, m_targetList);

View File

@ -486,7 +486,7 @@ RELATION(nam_mon_database, rel_mon_database, ODS_11_1, rel_virtual)
FIELD(f_mon_db_read_only, nam_mon_read_only, fld_flag_nullable, 0, ODS_11_1)
FIELD(f_mon_db_forced_writes, nam_mon_forced_writes, fld_flag_nullable, 0, ODS_11_1)
FIELD(f_mon_db_res_space, nam_mon_res_space, fld_flag_nullable, 0, ODS_11_1)
FIELD(f_mon_db_created, nam_mon_created, fld_time, 0, ODS_11_1)
FIELD(f_mon_db_created, nam_mon_created, fld_timestamp_tz, 0, ODS_11_1)
FIELD(f_mon_db_pages, nam_mon_pages, fld_counter, 0, ODS_11_1)
FIELD(f_mon_db_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)
FIELD(f_mon_db_backup_state, nam_mon_backup_state, fld_backup_state, 0, ODS_11_1)
@ -507,7 +507,7 @@ RELATION(nam_mon_attachments, rel_mon_attachments, ODS_11_1, rel_virtual)
FIELD(f_mon_att_remote_addr, nam_mon_remote_addr, fld_remote_addr, 0, ODS_11_1)
FIELD(f_mon_att_remote_pid, nam_mon_remote_pid, fld_pid, 0, ODS_11_1)
FIELD(f_mon_att_charset_id, nam_mon_charset_id, fld_charset_id, 0, ODS_11_1)
FIELD(f_mon_att_timestamp, nam_mon_timestamp, fld_time, 0, ODS_11_1)
FIELD(f_mon_att_timestamp, nam_mon_timestamp, fld_timestamp_tz, 0, ODS_11_1)
FIELD(f_mon_att_gc, nam_mon_gc, fld_flag_nullable, 0, ODS_11_1)
FIELD(f_mon_att_remote_process, nam_mon_remote_process, fld_file_name2, 0, ODS_11_1)
FIELD(f_mon_att_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)
@ -529,7 +529,7 @@ RELATION(nam_mon_transactions, rel_mon_transactions, ODS_11_1, rel_virtual)
FIELD(f_mon_tra_id, nam_mon_tra_id, fld_trans_id, 0, ODS_11_1)
FIELD(f_mon_tra_att_id, nam_mon_att_id, fld_att_id, 0, ODS_11_1)
FIELD(f_mon_tra_state, nam_mon_state, fld_state, 0, ODS_11_1)
FIELD(f_mon_tra_timestamp, nam_mon_timestamp, fld_time, 0, ODS_11_1)
FIELD(f_mon_tra_timestamp, nam_mon_timestamp, fld_timestamp_tz, 0, ODS_11_1)
FIELD(f_mon_tra_top, nam_mon_top, fld_trans_id, 0, ODS_11_1)
FIELD(f_mon_tra_oit, nam_mon_oit, fld_trans_id, 0, ODS_11_1)
FIELD(f_mon_tra_oat, nam_mon_oat, fld_trans_id, 0, ODS_11_1)
@ -547,7 +547,7 @@ RELATION(nam_mon_statements, rel_mon_statements, ODS_11_1, rel_virtual)
FIELD(f_mon_stmt_att_id, nam_mon_att_id, fld_att_id, 0, ODS_11_1)
FIELD(f_mon_stmt_tra_id, nam_mon_tra_id, fld_trans_id, 0, ODS_11_1)
FIELD(f_mon_stmt_state, nam_mon_state, fld_state, 0, ODS_11_1)
FIELD(f_mon_stmt_timestamp, nam_mon_timestamp, fld_time, 0, ODS_11_1)
FIELD(f_mon_stmt_timestamp, nam_mon_timestamp, fld_timestamp_tz, 0, ODS_11_1)
FIELD(f_mon_stmt_sql_text, nam_mon_sql_text, fld_source, 0, ODS_11_1)
FIELD(f_mon_stmt_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)
FIELD(f_mon_stmt_expl_plan, nam_mon_expl_plan, fld_source, 0, ODS_11_1)
@ -562,7 +562,7 @@ RELATION(nam_mon_calls, rel_mon_calls, ODS_11_1, rel_virtual)
FIELD(f_mon_call_caller_id, nam_mon_caller_id, fld_call_id, 0, ODS_11_1)
FIELD(f_mon_call_name, nam_mon_obj_name, fld_gnr_name, 0, ODS_11_1)
FIELD(f_mon_call_type, nam_mon_obj_type, fld_obj_type, 0, ODS_11_1)
FIELD(f_mon_call_timestamp, nam_mon_timestamp, fld_time, 0, ODS_11_1)
FIELD(f_mon_call_timestamp, nam_mon_timestamp, fld_timestamp_tz, 0, ODS_11_1)
FIELD(f_mon_call_src_line, nam_mon_src_line, fld_src_info, 0, ODS_11_1)
FIELD(f_mon_call_src_column, nam_mon_src_column, fld_src_info, 0, ODS_11_1)
FIELD(f_mon_call_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)

View File

@ -266,7 +266,7 @@ public:
ULONG req_flags; // misc request flags
Savepoint* req_savepoints; // Looper savepoint list
Savepoint* req_proc_sav_point; // procedure savepoint list
Firebird::TimeStamp req_timestamp_utc; // Start time of request
Firebird::TimeStamp req_gmt_timestamp; // Start time of request in GMT time zone
unsigned int req_timeout; // query timeout in milliseconds, set by the dsql_req::setupTimer
Firebird::RefPtr<TimeoutTimer> req_timer; // timeout timer, shared with dsql_req
@ -369,12 +369,19 @@ public:
Firebird::TimeStamp getLocalTimeStamp() const
{
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.utc_timestamp = req_timestamp_utc.value();
timeStampTz.utc_timestamp = req_gmt_timestamp.value();
timeStampTz.time_zone = Firebird::TimeZoneUtil::GMT_ZONE;
Firebird::TimeZoneUtil::localTimeStampToUtc(timeStampTz);
return Firebird::TimeZoneUtil::timeStampTzToTimeStamp(timeStampTz, req_attachment->att_current_timezone);
}
ISC_TIMESTAMP_TZ getTimeStampTz() const
{
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.utc_timestamp = req_gmt_timestamp.value();
timeStampTz.time_zone = req_attachment->att_current_timezone;
return timeStampTz;
}
};
// Flags for req_flags

View File

@ -175,7 +175,7 @@ public:
tra_resources(*p),
tra_context_vars(*p),
tra_lock_timeout(DEFAULT_LOCK_TIMEOUT),
tra_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
tra_timestamp(Firebird::TimeZoneUtil::getCurrentSystemTimeStamp()),
tra_stats(*p),
tra_open_cursors(*p),
tra_outer(outer),
@ -280,7 +280,7 @@ public:
UCHAR tra_callback_count; // callback count for 'execute statement'
SSHORT tra_lock_timeout; // in seconds, -1 means infinite, 0 means NOWAIT
ULONG tra_next_blob_id; // ID of the previous blob or array created in this transaction
const Firebird::TimeStamp tra_timestamp; // transaction start time
const ISC_TIMESTAMP_TZ tra_timestamp; // transaction start time
jrd_req* tra_requests; // Doubly linked list of requests active in this transaction
MonitoringSnapshot* tra_mon_snapshot; // Database state snapshot (for monitoring purposes)
RuntimeStatistics tra_stats;

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2018-08-31 12:44:00', 'JRD', 0, 893)
('2018-12-24 14:22:00', 'JRD', 0, 896)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -1000,6 +1000,9 @@ 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_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);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -899,6 +899,9 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '00', '000', 0, 890, 'plugin_name', NULL, NULL)
(-901, '42', '000', 0, 891, 'parameter_name', NULL, NULL)
(-901, 'HY', '000', 0, 892, 'file_starting_page_err', NULL, NULL)
(-901, '22', '009', 0, 893, 'invalid_timezone_offset', NULL, NULL)
(-901, '22', '009', 0, 894, 'invalid_timezone_region', NULL, NULL)
(-901, '22', '009', 0, 895, 'invalid_timezone_id', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)