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

Changing descriptors to store in memory date/time tz in UTC and usage of ICU for time zone regions.

This version is fixedly configured only with America/Sao_Paulo and America/Los_Angeles.
This commit is contained in:
Adriano dos Santos Fernandes 2018-03-18 17:08:50 -03:00
parent 8792dff315
commit 141f62611b
23 changed files with 746 additions and 461 deletions

View File

@ -352,6 +352,9 @@ fb_get_transaction_handle
fb_database_crypt_callback fb_database_crypt_callback
fb_dsql_set_timeout fb_dsql_set_timeout
isc_decode_sql_time_tz
isc_decode_timestamp_tz
# Other misc functions # Other misc functions
isc_ftof isc_ftof

View File

@ -357,6 +357,9 @@ EXPORTS
fb_get_transaction_handle fb_get_transaction_handle
fb_database_crypt_callback fb_database_crypt_callback
isc_decode_sql_time_tz
isc_decode_timestamp_tz
gds__trace gds__trace
gds__trace_raw gds__trace_raw
gds__trace_printer gds__trace_printer

View File

@ -24,10 +24,14 @@
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
*/ */
//// TODO: Configure ICU time zone data files.
//// TODO: Update Windows ICU.
#include "firebird.h" #include "firebird.h"
#include "../common/TimeZoneUtil.h" #include "../common/TimeZoneUtil.h"
#include "../common/StatusHolder.h" #include "../common/StatusHolder.h"
#include "../common/unicode_util.h"
#include "../common/classes/timestamp.h" #include "../common/classes/timestamp.h"
#include "unicode/ucal.h"
using namespace Firebird; using namespace Firebird;
@ -35,14 +39,13 @@ using namespace Firebird;
struct TimeZoneDesc struct TimeZoneDesc
{ {
USHORT id; const char* abbr; //// FIXME: remove
const char* abbr; const UChar* icuName;
}; };
//------------------------------------- //-------------------------------------
static SSHORT getDisplacement(const ISC_TIMESTAMP_TZ& timeStampTz); static const TimeZoneDesc& getDesc(USHORT timeZone);
static SSHORT getDisplacement(const ISC_TIMESTAMP& timeStampUtc, USHORT timeZone);
static inline bool isOffset(USHORT timeZone); static inline bool isOffset(USHORT timeZone);
static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm); static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm);
static USHORT makeFromRegion(const char* str, unsigned strLen); static USHORT makeFromRegion(const char* str, unsigned strLen);
@ -52,30 +55,92 @@ static void skipSpaces(const char*& p, const char* end);
//------------------------------------- //-------------------------------------
static const UChar TZSTR_GMT[] = {
'G', 'M', 'T', '\0'};
static const UChar TZSTR_AMERICA_SAO_PAULO[] = {
'A', 'm', 'e', 'r', 'i', 'c', 'a', '/', 'S', 'a', 'o', '_', 'P', 'a', 'u', 'l', 'o', '\0'};
static const UChar TZSTR_AMERICA_LOS_ANGELES[] = {
'A', 'm', 'e', 'r', 'i', 'c', 'a', '/', 'L', 'o', 's', '_', 'A', 'n', 'g', 'e', 'l', 'e', 's', '\0'};
// Do not change order of items in this array! The index corresponds to a TimeZone ID, which must be fixed!
static const TimeZoneDesc TIME_ZONE_LIST[] = { //// FIXME: static const TimeZoneDesc TIME_ZONE_LIST[] = { //// FIXME:
{0, "BRT"}, {"GMT", TZSTR_GMT},
{1, "BRST"} {"America/Sao_Paulo", TZSTR_AMERICA_SAO_PAULO},
{"America/Los_Angeles", TZSTR_AMERICA_LOS_ANGELES}
}; };
//------------------------------------- //-------------------------------------
//// FIXME: Windows and others ports. struct TimeZoneStartup
// Return the current user's time zone.
USHORT TimeZoneUtil::getCurrent()
{ {
//// FIXME: Return the time zone region instead of the offset. TimeZoneStartup(MemoryPool& p)
time_t rawtime; : systemTimeZone(TimeZoneUtil::UTC_ZONE)
time(&rawtime); {
UErrorCode icuErrorCode = U_ZERO_ERROR;
struct tm tm1; Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
if (!localtime_r(&rawtime, &tm1)) UCalendar* icuCalendar = icuLib.ucalOpen(NULL, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
system_call_failed::raise("localtime_r");
int sign = tm1.tm_gmtoff < 0 ? -1 : 1; if (!icuCalendar)
unsigned tzh = (unsigned) abs(int(tm1.tm_gmtoff / 60 / 60)); {
unsigned tzm = (unsigned) abs(int(tm1.tm_gmtoff / 60 % 60)); gds__log("ICU's ucal_open error opening the default callendar.");
return;
}
return makeFromOffset(sign, tzh, tzm); UChar buffer[TimeZoneUtil::MAX_SIZE];
bool found = false;
icuLib.ucalGetTimeZoneID(icuCalendar, buffer, FB_NELEM(buffer), &icuErrorCode);
if (!U_FAILURE(icuErrorCode))
{
for (unsigned i = 0; i < FB_NELEM(TIME_ZONE_LIST) && !found; ++i)
{
if (icuLib.ustrcmp(TIME_ZONE_LIST[i].icuName, buffer) == 0)
{
systemTimeZone = MAX_USHORT - i;
found = true;
}
}
}
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));
}
USHORT systemTimeZone;
};
static InitInstance<TimeZoneStartup> timeZoneStartup;
//-------------------------------------
// Return the current user's time zone.
USHORT TimeZoneUtil::getSystemTimeZone()
{
return timeZoneStartup().systemTimeZone;
} }
// Parses a time zone, offset- or region-based. // Parses a time zone, offset- or region-based.
@ -139,13 +204,7 @@ unsigned TimeZoneUtil::format(char* buffer, size_t bufferSize, USHORT timeZone)
} }
else else
{ {
if (MAX_USHORT - timeZone < FB_NELEM(TIME_ZONE_LIST)) strncpy(buffer, getDesc(timeZone).abbr, bufferSize);
strncpy(buffer, TIME_ZONE_LIST[MAX_USHORT - timeZone].abbr, bufferSize);
else
{
fb_assert(false);
strncpy(buffer, "*Invalid*", bufferSize);
}
p += strlen(buffer); p += strlen(buffer);
} }
@ -169,13 +228,36 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
displacement = offsetZoneToDisplacement(timeStampTz.timestamp_zone); displacement = offsetZoneToDisplacement(timeStampTz.timestamp_zone);
else else
{ {
ISC_TIMESTAMP ts1 = *(ISC_TIMESTAMP*) &timeStampTz; UErrorCode icuErrorCode = U_ZERO_ERROR;
ISC_TIMESTAMP ts2 = timeStampTzAtZone(timeStampTz, UTC_ZONE);
displacement = Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
((ts1.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + ts1.timestamp_time) -
(ts2.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + ts2.timestamp_time)) / UCalendar* icuCalendar = icuLib.ucalOpen(
(ISC_TIME_SECONDS_PRECISION * 60); getDesc(timeStampTz.timestamp_zone).icuName, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
SINT64 ticks = timeStampTz.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + timeStampTz.timestamp_time;
icuLib.ucalSetMillis(icuCalendar, (ticks - (40587 * TimeStamp::ISC_TICKS_PER_DAY)) / 10, &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis.");
}
displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
} }
*sign = displacement < 0 ? -1 : 1; *sign = displacement < 0 ? -1 : 1;
@ -185,95 +267,163 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
*tzm = displacement % 60; *tzm = displacement % 60;
} }
// Moves a time from one time zone to another. // Converts a time-tz to a time in a given zone.
ISC_TIME TimeZoneUtil::timeTzAtZone(const ISC_TIME_TZ& timeTz, USHORT atTimeZone) ISC_TIME TimeZoneUtil::timeTzToTime(const ISC_TIME_TZ& timeTz, USHORT toTimeZone)
{ {
//// TODO:
ISC_TIMESTAMP_TZ tempTimeStampTz; ISC_TIMESTAMP_TZ tempTimeStampTz;
tempTimeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date; tempTimeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date;
tempTimeStampTz.timestamp_time = timeTz.time_time; tempTimeStampTz.timestamp_time = timeTz.time_time;
tempTimeStampTz.timestamp_zone = timeTz.time_zone; tempTimeStampTz.timestamp_zone = timeTz.time_zone;
return timeStampTzAtZone(tempTimeStampTz, atTimeZone).timestamp_time; return timeStampTzToTimeStamp(tempTimeStampTz, toTimeZone).timestamp_time;
} }
// Moves a timestamp from one time zone to another. // Converts a timestamp-tz to a timestamp in a given zone.
ISC_TIMESTAMP TimeZoneUtil::timeStampTzAtZone(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT atTimeZone) ISC_TIMESTAMP TimeZoneUtil::timeStampTzToTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT toTimeZone)
{ {
SSHORT timeDisplacement = getDisplacement(timeStampTz); ISC_TIMESTAMP_TZ tempTimeStampTz = timeStampTz;
tempTimeStampTz.timestamp_zone = toTimeZone;
SINT64 ticks = timeStampTz.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + timeStampTz.timestamp_time - struct tm times;
(timeDisplacement * 60 * ISC_TIME_SECONDS_PRECISION); int fractions;
decodeTimeStamp(tempTimeStampTz, &times, &fractions);
SSHORT atDisplacement; return TimeStamp::encode_timestamp(&times, fractions);
}
if (isOffset(atTimeZone)) // Converts a time from local to UTC.
atDisplacement = offsetZoneToDisplacement(atTimeZone); void TimeZoneUtil::localTimeToUtc(ISC_TIME_TZ& timeTz)
{
//// TODO:
ISC_TIMESTAMP_TZ tempTimeStampTz;
tempTimeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date;
tempTimeStampTz.timestamp_time = timeTz.time_time;
tempTimeStampTz.timestamp_zone = timeTz.time_zone;
localTimeStampToUtc(tempTimeStampTz);
timeTz.time_time = tempTimeStampTz.timestamp_time;
}
// Converts a timestamp from its local datetime fields to UTC.
void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
{
int displacement;
if (isOffset(timeStampTz.timestamp_zone))
displacement = offsetZoneToDisplacement(timeStampTz.timestamp_zone);
else else
{ {
ISC_TIMESTAMP tempTimeStampUtc; tm times;
tempTimeStampUtc.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY; TimeStamp::decode_timestamp(*(ISC_TIMESTAMP*) &timeStampTz, &times, nullptr);
tempTimeStampUtc.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
atDisplacement = getDisplacement(tempTimeStampUtc, atTimeZone); UErrorCode icuErrorCode = U_ZERO_ERROR;
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
getDesc(timeStampTz.timestamp_zone).icuName, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
icuLib.ucalSetDateTime(icuCalendar, 1900 + times.tm_year, times.tm_mon, times.tm_mday,
times.tm_hour, times.tm_min, times.tm_sec, &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setDateTime.");
} }
ticks -= -atDisplacement * 60 * ISC_TIME_SECONDS_PRECISION; displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
}
SINT64 ticks = timeStampTz.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + timeStampTz.timestamp_time -
(displacement * 60 * ISC_TIME_SECONDS_PRECISION);
timeStampTz.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY;
timeStampTz.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
}
void TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, struct tm* times, int* fractions)
{
//// TODO:
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date;
timeStampTz.timestamp_time = timeTz.time_time;
timeStampTz.timestamp_zone = timeTz.time_zone;
decodeTimeStamp(timeStampTz, times, fractions);
}
void TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct tm* times, int* fractions)
{
SINT64 ticks = timeStampTz.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + timeStampTz.timestamp_time;
int displacement;
if (isOffset(timeStampTz.timestamp_zone))
displacement = offsetZoneToDisplacement(timeStampTz.timestamp_zone);
else
{
UErrorCode icuErrorCode = U_ZERO_ERROR;
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
getDesc(timeStampTz.timestamp_zone).icuName, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
icuLib.ucalSetMillis(icuCalendar, (ticks - (40587 * TimeStamp::ISC_TICKS_PER_DAY)) / 10, &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis.");
}
displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
}
ticks += displacement * 60 * ISC_TIME_SECONDS_PRECISION;
ISC_TIMESTAMP ts; ISC_TIMESTAMP ts;
ts.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY; ts.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY;
ts.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY; ts.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
return ts; TimeStamp::decode_timestamp(ts, times, fractions);
} }
//------------------------------------- //-------------------------------------
// Gets the displacement that a timestamp (with time zone) is from UTC. static const TimeZoneDesc& getDesc(USHORT timeZone)
static SSHORT getDisplacement(const ISC_TIMESTAMP_TZ& timeStampTz)
{ {
const USHORT timeZone = timeStampTz.timestamp_zone; if (MAX_USHORT - timeZone < FB_NELEM(TIME_ZONE_LIST))
return TIME_ZONE_LIST[MAX_USHORT - timeZone];
if (isOffset(timeZone)) status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone id"); //// TODO:
return offsetZoneToDisplacement(timeZone); return *(TimeZoneDesc*) nullptr;
else
{
//// FIXME:
switch (MAX_USHORT - timeZone)
{
case 0: // BRT
return -(3 * 60);
case 1: // BRST
return -(2 * 60);
default:
fb_assert(false);
return 0;
}
}
}
// Gets the displacement necessary to convert a UTC timestamp to another time zone.
static SSHORT getDisplacement(const ISC_TIMESTAMP& timeStampUtc, USHORT timeZone)
{
if (isOffset(timeZone))
return offsetZoneToDisplacement(timeZone);
else
{
//// FIXME:
switch (MAX_USHORT - timeZone)
{
case 0: // BRT
return -(3 * 60);
case 1: // BRST
return -(2 * 60);
default:
fb_assert(false);
return 0;
}
}
} }
// Returns true if the time zone is offset-based or false if region-based. // Returns true if the time zone is offset-based or false if region-based.
@ -300,7 +450,7 @@ static USHORT makeFromRegion(const char* str, unsigned strLen)
const char* start = str; const char* start = str;
while (str < end && ((*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z'))) while (str < end && ((*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z') || *str == '_' || *str == '/'))
++str; ++str;
unsigned len = str - start; unsigned len = str - start;

View File

@ -36,10 +36,12 @@ class TimeZoneUtil
public: public:
static const unsigned ONE_DAY = 24 * 60; // used for offset encoding static const unsigned ONE_DAY = 24 * 60; // used for offset encoding
static const USHORT UTC_ZONE = ONE_DAY + 0; static const USHORT UTC_ZONE = ONE_DAY + 0;
static const unsigned MAX_LEN = 6;
static const unsigned MAX_LEN = 25; //// FIXME:
static const unsigned MAX_SIZE = MAX_LEN + 1;
public: public:
static USHORT getCurrent(); static USHORT getSystemTimeZone();
static USHORT parse(const char* str, unsigned strLen); static USHORT parse(const char* str, unsigned strLen);
static unsigned format(char* buffer, size_t bufferSize, USHORT timeZone); static unsigned format(char* buffer, size_t bufferSize, USHORT timeZone);
@ -48,8 +50,14 @@ public:
static void extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign, unsigned* tzh, unsigned* tzm); static void extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign, unsigned* tzh, unsigned* tzm);
static ISC_TIME timeTzAtZone(const ISC_TIME_TZ& timeTz, USHORT atTimeZone); static ISC_TIME timeTzToTime(const ISC_TIME_TZ& timeTz, USHORT toTimeZone);
static ISC_TIMESTAMP timeStampTzAtZone(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT atTimeZone); static ISC_TIMESTAMP timeStampTzToTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT toTimeZone);
static void localTimeToUtc(ISC_TIME_TZ& timeTz);
static void localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz);
static void decodeTime(const ISC_TIME_TZ& timeTz, struct tm* times, int* fractions = NULL);
static void decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, struct tm* times, int* fractions = NULL);
}; };
} // namespace Firebird } // namespace Firebird

View File

@ -653,10 +653,14 @@ void CVT_string_to_datetime(const dsc* desc,
*(ISC_TIMESTAMP*) date = Firebird::TimeStamp::getCurrentTimeStamp().value(); *(ISC_TIMESTAMP*) date = Firebird::TimeStamp::getCurrentTimeStamp().value();
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz) if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz)
((ISC_TIMESTAMP_TZ*) date)->timestamp_zone = TimeZoneUtil::getCurrent(); date->timestamp_zone = cb->getSessionTimeZone();
if (strcmp(temp, NOW) == 0) if (strcmp(temp, NOW) == 0)
{
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz)
TimeZoneUtil::localTimeStampToUtc(*date);
return; return;
}
if (expect_type == expect_sql_time || expect_type == expect_sql_time_tz) if (expect_type == expect_sql_time || expect_type == expect_sql_time_tz)
{ {
@ -666,6 +670,9 @@ void CVT_string_to_datetime(const dsc* desc,
date->timestamp_time = 0; date->timestamp_time = 0;
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz)
TimeZoneUtil::localTimeStampToUtc(*date);
if (strcmp(temp, TODAY) == 0) if (strcmp(temp, TODAY) == 0)
return; return;
@ -767,7 +774,8 @@ void CVT_string_to_datetime(const dsc* desc,
return; return;
} }
USHORT zone = cb->getSessionTimeZone(); USHORT sessionTimeZone = cb->getSessionTimeZone();
USHORT zone = sessionTimeZone;
if (expect_type != expect_sql_date) if (expect_type != expect_sql_date)
{ {
@ -879,12 +887,13 @@ void CVT_string_to_datetime(const dsc* desc,
} }
else else
{ {
// The date portion isn't needed for time - but to // Fetch current date
// keep the conversion in/out of isc_time clean lets tm times2;
// initialize it properly anyway Firebird::TimeStamp::getCurrentTimeStamp().decode(&times2);
times.tm_year = 0;
times.tm_mon = 0; times.tm_year = times2.tm_year;
times.tm_mday = 1; times.tm_mon = times2.tm_mon;
times.tm_mday = times2.tm_mday;
} }
// Handle time values out of range - note possibility of 60 for // Handle time values out of range - note possibility of 60 for
@ -952,15 +961,21 @@ void CVT_string_to_datetime(const dsc* desc,
date->timestamp_time += components[6]; date->timestamp_time += components[6];
date->timestamp_zone = zone; date->timestamp_zone = zone;
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz || zone != sessionTimeZone)
TimeZoneUtil::localTimeStampToUtc(*date);
if (zone != sessionTimeZone)
{
if (expect_type == expect_sql_time) if (expect_type == expect_sql_time)
{ {
ISC_TIME_TZ timeTz; ISC_TIME_TZ timeTz;
timeTz.time_time = date->timestamp_time; timeTz.time_time = date->timestamp_time;
timeTz.time_zone = zone; timeTz.time_zone = zone;
date->timestamp_time = TimeZoneUtil::timeTzAtZone(timeTz, cb->getSessionTimeZone()); date->timestamp_time = TimeZoneUtil::timeTzToTime(timeTz, sessionTimeZone);
} }
else if (expect_type == expect_timestamp) else if (expect_type == expect_timestamp)
*(ISC_TIMESTAMP*) date = TimeZoneUtil::timeStampTzAtZone(*date, cb->getSessionTimeZone()); *(ISC_TIMESTAMP*) date = TimeZoneUtil::timeStampTzToTimeStamp(*date, sessionTimeZone);
}
} }
@ -1543,13 +1558,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
tsTz.timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time; tsTz.timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time;
tsTz.timestamp_zone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone; tsTz.timestamp_zone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
*(ISC_TIMESTAMP*) to->dsc_address = *(ISC_TIMESTAMP*) to->dsc_address =
TimeZoneUtil::timeStampTzAtZone(tsTz, cb->getSessionTimeZone()); TimeZoneUtil::timeStampTzToTimeStamp(tsTz, cb->getSessionTimeZone());
return; return;
} }
case dtype_timestamp_tz: case dtype_timestamp_tz:
*(ISC_TIMESTAMP*) to->dsc_address = *(ISC_TIMESTAMP*) to->dsc_address =
TimeZoneUtil::timeStampTzAtZone(*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone()); TimeZoneUtil::timeStampTzToTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone());
return; return;
default: default:
@ -1588,10 +1603,12 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = cb->getCurDate(); ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = cb->getCurDate();
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time; ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone(); ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*(ISC_TIMESTAMP_TZ*) to->dsc_address);
return; return;
case dtype_sql_time_tz: case dtype_sql_time_tz:
// SQL: Copy date fields from CURRENT_DATE and time and time zone fields from the source. // SQL: Copy date fields from CURRENT_DATE and time and time zone fields from the source.
//// FIXME:
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = cb->getCurDate(); ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = cb->getCurDate();
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time; ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone; ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
@ -1601,11 +1618,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = *(GDS_DATE*) from->dsc_address; ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_date = *(GDS_DATE*) from->dsc_address;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = 0; ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_time = 0;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone(); ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*(ISC_TIMESTAMP_TZ*) to->dsc_address);
return; return;
case dtype_timestamp: case dtype_timestamp:
*(ISC_TIMESTAMP*) to->dsc_address = *(ISC_TIMESTAMP*) from->dsc_address; *(ISC_TIMESTAMP*) to->dsc_address = *(ISC_TIMESTAMP*) from->dsc_address;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone(); ((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*((ISC_TIMESTAMP_TZ*) to->dsc_address));
return; return;
default: default:
@ -1644,7 +1663,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
return; return;
case dtype_timestamp_tz: case dtype_timestamp_tz:
*(GDS_DATE*) to->dsc_address = TimeZoneUtil::timeStampTzAtZone( *(GDS_DATE*) to->dsc_address = TimeZoneUtil::timeStampTzToTimeStamp(
*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone()).timestamp_date; *(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone()).timestamp_date;
return; return;
@ -1683,7 +1702,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_sql_time_tz: case dtype_sql_time_tz:
*(ISC_TIME*) to->dsc_address = *(ISC_TIME*) to->dsc_address =
TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) from->dsc_address, cb->getSessionTimeZone()); TimeZoneUtil::timeTzToTime(*(ISC_TIME_TZ*) from->dsc_address, cb->getSessionTimeZone());
return; return;
case dtype_timestamp: case dtype_timestamp:
@ -1691,7 +1710,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
return; return;
case dtype_timestamp_tz: case dtype_timestamp_tz:
*(GDS_TIME*) to->dsc_address = TimeZoneUtil::timeStampTzAtZone( *(GDS_TIME*) to->dsc_address = TimeZoneUtil::timeStampTzToTimeStamp(
*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone()).timestamp_time; *(ISC_TIMESTAMP_TZ*) from->dsc_address, cb->getSessionTimeZone()).timestamp_time;
return; return;
@ -1731,11 +1750,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_sql_time: case dtype_sql_time:
*(ISC_TIME*) to->dsc_address = *(ISC_TIME*) from->dsc_address; *(ISC_TIME*) to->dsc_address = *(ISC_TIME*) from->dsc_address;
((ISC_TIME_TZ*) to->dsc_address)->time_zone = cb->getSessionTimeZone(); ((ISC_TIME_TZ*) to->dsc_address)->time_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeToUtc(*(ISC_TIME_TZ*) to->dsc_address);
return; return;
case dtype_timestamp: case dtype_timestamp:
((ISC_TIME_TZ*) to->dsc_address)->time_time = ((GDS_TIMESTAMP*) from->dsc_address)->timestamp_time; ((ISC_TIME_TZ*) to->dsc_address)->time_time = ((GDS_TIMESTAMP*) from->dsc_address)->timestamp_time;
((ISC_TIME_TZ*) to->dsc_address)->time_zone = cb->getSessionTimeZone(); ((ISC_TIME_TZ*) to->dsc_address)->time_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeToUtc(*(ISC_TIME_TZ*) to->dsc_address);
return; return;
case dtype_timestamp_tz: case dtype_timestamp_tz:
@ -2206,47 +2227,45 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
memset(&times, 0, sizeof(struct tm)); memset(&times, 0, sizeof(struct tm));
int fractions = 0; int fractions = 0;
USHORT timezone;
switch (from->dsc_dtype) switch (from->dsc_dtype)
{ {
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz:
Firebird::TimeStamp::decode_time(*(GDS_TIME*) from->dsc_address, Firebird::TimeStamp::decode_time(*(GDS_TIME*) from->dsc_address,
&times.tm_hour, &times.tm_min, &times.tm_sec, &fractions); &times.tm_hour, &times.tm_min, &times.tm_sec, &fractions);
break; break;
case dtype_sql_time_tz:
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address, &times, &fractions);
timezone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
break;
case dtype_sql_date: case dtype_sql_date:
Firebird::TimeStamp::decode_date(*(GDS_DATE *) from->dsc_address, &times); Firebird::TimeStamp::decode_date(*(GDS_DATE *) from->dsc_address, &times);
break; break;
case dtype_timestamp: case dtype_timestamp:
case dtype_timestamp_tz:
cb->isVersion4(version4); // Used in the conversion to text some lines below. cb->isVersion4(version4); // Used in the conversion to text some lines below.
Firebird::TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) from->dsc_address, &times, &fractions); Firebird::TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) from->dsc_address, &times, &fractions);
break; break;
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);
timezone = ((ISC_TIMESTAMP_TZ*) from->dsc_address)->timestamp_zone;
break;
default: default:
fb_assert(false); fb_assert(false);
cb->err(Arg::Gds(isc_badblk)); // internal error cb->err(Arg::Gds(isc_badblk)); // internal error
break; break;
} }
USHORT timezone;
switch (from->dsc_dtype)
{
case dtype_sql_time_tz:
timezone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
break;
case dtype_timestamp_tz:
timezone = ((ISC_TIMESTAMP_TZ*) from->dsc_address)->timestamp_zone;
break;
}
// Decode the timestamp into human readable terms // Decode the timestamp into human readable terms
TEXT temp[36]; // yyyy-mm-dd hh:mm:ss.tttt +th:tm OR dd-MMM-yyyy hh:mm:ss.tttt +th:tm // yyyy-mm-dd hh:mm:ss.tttt +th:tm OR dd-MMM-yyyy hh:mm:ss.tttt +th:tm
TEXT temp[27 + TimeZoneUtil::MAX_LEN];
TEXT* p = temp; TEXT* p = temp;
// Make a textual date for data types that include it // Make a textual date for data types that include it
@ -3251,7 +3270,9 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
case dtype_blob: case dtype_blob:
case dtype_sql_date: case dtype_sql_date:
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz:
case dtype_timestamp: case dtype_timestamp:
case dtype_timestamp_tz:
case dtype_array: case dtype_array:
case dtype_dbkey: case dtype_dbkey:
case dtype_boolean: case dtype_boolean:
@ -3408,7 +3429,7 @@ namespace
USHORT CommonCallbacks::getSessionTimeZone() USHORT CommonCallbacks::getSessionTimeZone()
{ {
return TimeZoneUtil::UTC_ZONE; return TimeZoneUtil::getSystemTimeZone();
} }
void CommonCallbacks::isVersion4(bool& /*v4*/) void CommonCallbacks::isVersion4(bool& /*v4*/)

View File

@ -27,6 +27,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "../common/dsc.h" #include "../common/dsc.h"
#include "../common/TimeZoneUtil.h"
#include "../jrd/ibase.h" #include "../jrd/ibase.h"
#include "../jrd/intl.h" #include "../jrd/intl.h"
#include "../yvalve/gds_proto.h" #include "../yvalve/gds_proto.h"
@ -68,8 +69,8 @@ static const USHORT _DSC_convert_to_text_length[DTYPE_TYPE_MAX] =
23, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4) 23, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4)
42, // dtype_dec128 +- . e +- coeff + exp 42, // dtype_dec128 +- . e +- coeff + exp
36, // dtype_dec_fixed coeff(34) + 1(+-) + 1(.) 36, // dtype_dec_fixed coeff(34) + 1(+-) + 1(.)
20, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN 14 + TimeZoneUtil::MAX_LEN, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN
31 // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN 25 + TimeZoneUtil::MAX_LEN // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN
}; };
// Unimplemented names are in lowercase & <brackets> // Unimplemented names are in lowercase & <brackets>

View File

@ -277,6 +277,19 @@ private:
(Arg::Gds(isc_random) << diag).raise(); (Arg::Gds(isc_random) << diag).raise();
} }
} }
inModule = formatAndLoad(inTemplate, aMajorVersion, aMinorVersion);
if (!inModule)
return;
getEntryPoint("u_strcmp", inModule, ustrcmp);
getEntryPoint("ucal_open", inModule, ucalOpen);
getEntryPoint("ucal_close", inModule, ucalClose);
getEntryPoint("ucal_setMillis", inModule, ucalSetMillis);
getEntryPoint("ucal_get", inModule, ucalGet);
getEntryPoint("ucal_setDateTime", inModule, ucalSetDateTime);
getEntryPoint("ucal_getTimeZoneID", inModule, ucalGetTimeZoneID);
} }
public: public:
@ -302,6 +315,7 @@ public:
private: private:
AutoPtr<ModuleLoader::Module> module; AutoPtr<ModuleLoader::Module> module;
AutoPtr<ModuleLoader::Module> inModule;
}; };
static ImplementConversionICU* convIcu = NULL; static ImplementConversionICU* convIcu = NULL;

View File

@ -32,6 +32,7 @@
#include "../common/os/mod_loader.h" #include "../common/os/mod_loader.h"
#include "../common/classes/fb_string.h" #include "../common/classes/fb_string.h"
#include <unicode/ucnv.h> #include <unicode/ucnv.h>
#include <unicode/ucal.h>
struct UCollator; struct UCollator;
struct USet; struct USet;
@ -120,6 +121,18 @@ public:
int8_t (U_EXPORT2* ucnv_getMaxCharSize) (const UConverter *converter); int8_t (U_EXPORT2* ucnv_getMaxCharSize) (const UConverter *converter);
int8_t (U_EXPORT2* ucnv_getMinCharSize) (const UConverter *converter); int8_t (U_EXPORT2* ucnv_getMinCharSize) (const UConverter *converter);
int32_t (U_EXPORT2* ustrcmp) (const UChar* s1, const UChar* s2);
UCalendar* (U_EXPORT2* ucalOpen) (const UChar* zoneID, int32_t len, const char* locale, UCalendarType type,
UErrorCode* err);
void (U_EXPORT2* ucalClose) (UCalendar* cal);
void (U_EXPORT2* ucalSetMillis) (UCalendar* cal, UDate dateTime, UErrorCode* err);
int32_t (U_EXPORT2* ucalGet) (UCalendar* cal, UCalendarDateFields field, UErrorCode* err);
void (U_EXPORT2* ucalSetDateTime) (UCalendar* cal, int32_t year, int32_t month, int32_t date, int32_t hour,
int32_t minute, int32_t second, UErrorCode* err);
int32_t (U_EXPORT2* ucalGetTimeZoneID) (const UCalendar* cal, UChar* result, int32_t resultLength,
UErrorCode *status);
int vMajor, vMinor; int vMajor, vMinor;
}; };

View File

@ -673,15 +673,15 @@ void AvgAggNode::aggInit(thread_db* tdbb, jrd_req* request) const
} }
} }
void AvgAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* desc) const void AvgAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const
{ {
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset); impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
++impure->vlux_count; ++impure->vlux_count;
if (dialect1) if (dialect1)
ArithmeticNode::add(desc, impure, this, blr_add); ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
else else
ArithmeticNode::add2(desc, impure, this, blr_add); ArithmeticNode::add2(tdbb, desc, impure, this, blr_add);
} }
dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
@ -1197,15 +1197,15 @@ void SumAggNode::aggInit(thread_db* tdbb, jrd_req* request) const
} }
} }
void SumAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* desc) const void SumAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const
{ {
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset); impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
++impure->vlux_count; ++impure->vlux_count;
if (dialect1) if (dialect1)
ArithmeticNode::add(desc, impure, this, blr_add); ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
else else
ArithmeticNode::add2(desc, impure, this, blr_add); ArithmeticNode::add2(tdbb, desc, impure, this, blr_add);
} }
dsc* SumAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const dsc* SumAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const

View File

@ -177,7 +177,7 @@ static const SCHAR DIALECT_1_TIMESTAMP_SCALE = 0;
static bool couldBeDate(const dsc desc); static bool couldBeDate(const dsc desc);
static SINT64 getDayFraction(const dsc* d); static SINT64 getDayFraction(const dsc* d);
static SINT64 getTimeStampToIscTicks(const dsc* d, bool); static SINT64 getTimeStampToIscTicks(thread_db* tdbb, const dsc* d);
static bool isDateAndTime(const dsc& d1, const dsc& d2); static bool isDateAndTime(const dsc& d1, const dsc& d2);
static void setParameterInfo(dsql_par* parameter, const dsql_ctx* context); static void setParameterInfo(dsql_par* parameter, const dsql_ctx* context);
@ -1811,7 +1811,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
case blr_add: case blr_add:
case blr_subtract: case blr_subtract:
return add(desc2, impure, this, blrOp); return add(tdbb, desc2, impure, this, blrOp);
case blr_divide: case blr_divide:
{ {
@ -1848,7 +1848,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
case blr_add: case blr_add:
case blr_subtract: case blr_subtract:
return add2(desc2, impure, this, blrOp); return add2(tdbb, desc2, impure, this, blrOp);
case blr_multiply: case blr_multiply:
return multiply2(desc2, impure); return multiply2(desc2, impure);
@ -1864,10 +1864,10 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const
// Add (or subtract) the contents of a descriptor to value block, with dialect-1 semantics. // Add (or subtract) the contents of a descriptor to value block, with dialect-1 semantics.
// This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?) // This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?)
dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp) dsc* ArithmeticNode::add(thread_db* tdbb, const dsc* desc, impure_value* value, const ValueExprNode* node,
const UCHAR blrOp)
{ {
const ArithmeticNode* arithmeticNode = nodeAs<ArithmeticNode>(node); const ArithmeticNode* arithmeticNode = nodeAs<ArithmeticNode>(node);
thread_db* tdbb = JRD_get_thread_data();
#ifdef DEV_BUILD #ifdef DEV_BUILD
const SubQueryNode* subQueryNode = nodeAs<SubQueryNode>(node); const SubQueryNode* subQueryNode = nodeAs<SubQueryNode>(node);
@ -1885,7 +1885,7 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo
if (node->nodFlags & FLAG_DATE) if (node->nodFlags & FLAG_DATE)
{ {
fb_assert(arithmeticNode); fb_assert(arithmeticNode);
return arithmeticNode->addDateTime(desc, value); return arithmeticNode->addDateTime(tdbb, desc, value);
} }
// Handle decimal arithmetic // Handle decimal arithmetic
@ -1964,7 +1964,8 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo
// Add (or subtract) the contents of a descriptor to value block, with dialect-3 semantics, as in // Add (or subtract) the contents of a descriptor to value block, with dialect-3 semantics, as in
// the blr_add, blr_subtract, and blr_agg_total verbs following a blr_version5. // the blr_add, blr_subtract, and blr_agg_total verbs following a blr_version5.
dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp) dsc* ArithmeticNode::add2(thread_db* tdbb, const dsc* desc, impure_value* value, const ValueExprNode* node,
const UCHAR blrOp)
{ {
const ArithmeticNode* arithmeticNode = nodeAs<ArithmeticNode>(node); const ArithmeticNode* arithmeticNode = nodeAs<ArithmeticNode>(node);
@ -1980,11 +1981,9 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN
if (node->nodFlags & FLAG_DATE) if (node->nodFlags & FLAG_DATE)
{ {
fb_assert(arithmeticNode); fb_assert(arithmeticNode);
return arithmeticNode->addDateTime(desc, value); return arithmeticNode->addDateTime(tdbb, desc, value);
} }
thread_db* tdbb = JRD_get_thread_data();
// Handle decimal arithmetic // Handle decimal arithmetic
if (node->nodFlags & FLAG_DECFLOAT) if (node->nodFlags & FLAG_DECFLOAT)
@ -2490,7 +2489,7 @@ dsc* ArithmeticNode::divide2(const dsc* desc, impure_value* value) const
} }
// Vector out to one of the actual datetime addition routines. // Vector out to one of the actual datetime addition routines.
dsc* ArithmeticNode::addDateTime(const dsc* desc, impure_value* value) const dsc* ArithmeticNode::addDateTime(thread_db* tdbb, const dsc* desc, impure_value* value) const
{ {
BYTE dtype; // Which addition routine to use? BYTE dtype; // Which addition routine to use?
@ -2526,7 +2525,7 @@ dsc* ArithmeticNode::addDateTime(const dsc* desc, impure_value* value) const
{ {
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz: case dtype_sql_time_tz:
return addSqlTime(desc, value); return addSqlTime(tdbb, desc, value);
case dtype_sql_date: case dtype_sql_date:
return addSqlDate(desc, value); return addSqlDate(desc, value);
@ -2540,7 +2539,7 @@ dsc* ArithmeticNode::addDateTime(const dsc* desc, impure_value* value) const
default: default:
// This needs to handle a dtype_sql_date + dtype_sql_time // This needs to handle a dtype_sql_date + dtype_sql_time
// For historical reasons prior to V6 - handle any types for timestamp arithmetic // For historical reasons prior to V6 - handle any types for timestamp arithmetic
return addTimeStamp(desc, value); return addTimeStamp(tdbb, desc, value);
} }
return NULL; return NULL;
@ -2620,78 +2619,67 @@ dsc* ArithmeticNode::addSqlDate(const dsc* desc, impure_value* value) const
// TIME - TIME Result is SLONG, scale -4 // TIME - TIME Result is SLONG, scale -4
// TIME +/- NUMERIC Numeric is interpreted as seconds DECIMAL(*,4). // TIME +/- NUMERIC Numeric is interpreted as seconds DECIMAL(*,4).
// NUMERIC +/- TIME Numeric is interpreted as seconds DECIMAL(*,4). // NUMERIC +/- TIME Numeric is interpreted as seconds DECIMAL(*,4).
dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const dsc* ArithmeticNode::addSqlTime(thread_db* tdbb, const dsc* desc, impure_value* value) const
{ {
fb_assert(blrOp == blr_add || blrOp == blr_subtract); fb_assert(blrOp == blr_add || blrOp == blr_subtract);
dsc* result = &value->vlu_desc; dsc* result = &value->vlu_desc;
thread_db* tdbb = JRD_get_thread_data();
Attachment* const attachment = tdbb->getAttachment(); Attachment* const attachment = tdbb->getAttachment();
fb_assert(value->vlu_desc.isTime() || desc->isTime()); fb_assert(value->vlu_desc.isTime() || desc->isTime());
bool op1_is_time = value->vlu_desc.isTime(); const dsc* op1_desc = &value->vlu_desc;
bool op2_is_time = desc->isTime(); const dsc* op2_desc = desc;
bool op1_is_tz = value->vlu_desc.isDateTimeTz();
bool op2_is_tz = desc->isDateTimeTz(); bool op1_is_time = op1_desc->isTime();
bool op2_is_time = op2_desc->isTime();
Nullable<USHORT> op1_tz, op2_tz;
if (op1_desc->dsc_dtype == dtype_sql_time_tz)
op1_tz = ((ISC_TIME_TZ*) op1_desc->dsc_address)->time_zone;
if (op2_desc->dsc_dtype == dtype_sql_time_tz)
op2_tz = ((ISC_TIME_TZ*) op2_desc->dsc_address)->time_zone;
dsc op1_tz_desc, op2_tz_desc;
ISC_TIME_TZ op1_time_tz, op2_time_tz;
if (op1_desc->dsc_dtype == dtype_sql_time && op2_is_time && op2_tz.specified)
{
op1_tz_desc.makeTimeTz(&op1_time_tz);
MOV_move(tdbb, const_cast<dsc*>(op1_desc), &op1_tz_desc);
op1_desc = &op1_tz_desc;
}
if (op2_desc->dsc_dtype == dtype_sql_time && op1_is_time && op1_tz.specified)
{
op2_tz_desc.makeTimeTz(&op2_time_tz);
MOV_move(tdbb, const_cast<dsc*>(op2_desc), &op2_tz_desc);
op2_desc = &op2_tz_desc;
}
// Coerce operand1 to a count of seconds // Coerce operand1 to a count of seconds
USHORT tz1 = TimeZoneUtil::UTC_ZONE;
SINT64 d1; SINT64 d1;
if (op1_is_time) if (op1_is_time)
{ {
if (op1_is_tz) d1 = *(GDS_TIME*) op1_desc->dsc_address;
tz1 = ((ISC_TIME_TZ*) value->vlu_desc.dsc_address)->time_zone;
if (blrOp == blr_subtract && op2_is_time && (op1_is_tz != op2_is_tz || (op1_is_tz && op2_is_tz)))
{
if (op1_is_tz)
d1 = TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) value->vlu_desc.dsc_address, TimeZoneUtil::UTC_ZONE);
else
{
ISC_TIME_TZ localTimeTz;
localTimeTz.time_time = *(ISC_TIME*) value->vlu_desc.dsc_address;
localTimeTz.time_zone = attachment->att_current_timezone;
d1 = TimeZoneUtil::timeTzAtZone(localTimeTz, TimeZoneUtil::UTC_ZONE);
}
}
else
d1 = *(GDS_TIME*) value->vlu_desc.dsc_address;
fb_assert(d1 >= 0 && d1 < ISC_TICKS_PER_DAY); fb_assert(d1 >= 0 && d1 < ISC_TICKS_PER_DAY);
} }
else else
d1 = MOV_get_int64(tdbb, &value->vlu_desc, ISC_TIME_SECONDS_PRECISION_SCALE); d1 = MOV_get_int64(tdbb, op1_desc, ISC_TIME_SECONDS_PRECISION_SCALE);
// Coerce operand2 to a count of seconds // Coerce operand2 to a count of seconds
USHORT tz2 = TimeZoneUtil::UTC_ZONE;
SINT64 d2; SINT64 d2;
if (op2_is_time) if (op2_is_time)
{ {
if (op2_is_tz) d2 = *(GDS_TIME*) op2_desc->dsc_address;
tz2 = ((ISC_TIME_TZ*) desc->dsc_address)->time_zone;
if (blrOp == blr_subtract && op1_is_time && (op1_is_tz != op2_is_tz || (op1_is_tz && op2_is_tz)))
{
if (op2_is_tz)
d2 = TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) desc->dsc_address, TimeZoneUtil::UTC_ZONE);
else
{
ISC_TIME_TZ localTimeTz;
localTimeTz.time_time = *(ISC_TIME*) desc->dsc_address;
localTimeTz.time_zone = attachment->att_current_timezone;
d2 = TimeZoneUtil::timeTzAtZone(localTimeTz, TimeZoneUtil::UTC_ZONE);
}
}
else
d2 = *(GDS_TIME*) desc->dsc_address;
fb_assert(d2 >= 0 && d2 < ISC_TICKS_PER_DAY); fb_assert(d2 >= 0 && d2 < ISC_TICKS_PER_DAY);
} }
else else
d2 = MOV_get_int64(tdbb, desc, ISC_TIME_SECONDS_PRECISION_SCALE); d2 = MOV_get_int64(tdbb, op2_desc, ISC_TIME_SECONDS_PRECISION_SCALE);
if (blrOp == blr_subtract && op1_is_time && op2_is_time) if (blrOp == blr_subtract && op1_is_time && op2_is_time)
{ {
@ -2732,18 +2720,18 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const
value->vlu_misc.vlu_sql_time_tz.time_time = d2; value->vlu_misc.vlu_sql_time_tz.time_time = d2;
result->dsc_dtype = op1_is_tz || op2_is_tz ? dtype_sql_time_tz : dtype_sql_time; result->dsc_dtype = op1_tz.specified || op2_tz.specified ? dtype_sql_time_tz : dtype_sql_time;
result->dsc_length = type_lengths[result->dsc_dtype]; result->dsc_length = type_lengths[result->dsc_dtype];
result->dsc_scale = 0; result->dsc_scale = 0;
result->dsc_sub_type = 0; result->dsc_sub_type = 0;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_sql_time_tz; result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_sql_time_tz;
fb_assert(!(op1_is_tz && op2_is_tz)); fb_assert(!(op1_tz.specified && op2_tz.specified));
if (op1_is_tz) if (op1_tz.specified)
((ISC_TIME_TZ*) result->dsc_address)->time_zone = tz1; value->vlu_misc.vlu_sql_time_tz.time_zone = op1_tz.value;
else if (op2_is_tz) else if (op2_tz.specified)
((ISC_TIME_TZ*) result->dsc_address)->time_zone = tz2; value->vlu_misc.vlu_sql_time_tz.time_zone = op2_tz.value;
return result; return result;
} }
@ -2754,26 +2742,51 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const
// NUMERIC +/- TIMESTAMP Numeric is interpreted as days DECIMAL(*,*). // NUMERIC +/- TIMESTAMP Numeric is interpreted as days DECIMAL(*,*).
// DATE + TIME // DATE + TIME
// TIME + DATE // TIME + DATE
dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const dsc* ArithmeticNode::addTimeStamp(thread_db* tdbb, const dsc* desc, impure_value* value) const
{ {
fb_assert(blrOp == blr_add || blrOp == blr_subtract); fb_assert(blrOp == blr_add || blrOp == blr_subtract);
bool op1_is_tz = value->vlu_desc.isDateTimeTz(); const dsc* op1_desc = &value->vlu_desc;
bool op2_is_tz = desc->isDateTimeTz(); const dsc* op2_desc = desc;
USHORT tz1 = TimeZoneUtil::UTC_ZONE;
USHORT tz2 = TimeZoneUtil::UTC_ZONE;
if (op1_is_tz) Nullable<USHORT> op1_tz, op2_tz;
if (op1_desc->dsc_dtype == dtype_sql_time_tz)
op1_tz = ((ISC_TIME_TZ*) op1_desc->dsc_address)->time_zone;
else if (op1_desc->dsc_dtype == dtype_timestamp_tz)
op1_tz = ((ISC_TIMESTAMP_TZ*) op1_desc->dsc_address)->timestamp_zone;
if (op2_desc->dsc_dtype == dtype_sql_time_tz)
op2_tz = ((ISC_TIME_TZ*) op2_desc->dsc_address)->time_zone;
else if (op2_desc->dsc_dtype == dtype_timestamp_tz)
op2_tz = ((ISC_TIMESTAMP_TZ*) op2_desc->dsc_address)->timestamp_zone;
dsc op1_tz_desc, op2_tz_desc;
ISC_TIMESTAMP_TZ op1_timestamp_tz, op2_timestamp_tz;
ISC_TIME_TZ op1_time_tz, op2_time_tz;
if ((op1_desc->dsc_dtype == dtype_sql_time || op1_desc->dsc_dtype == dtype_timestamp) &&
op2_desc->isDateTime() && op2_tz.specified)
{ {
tz1 = value->vlu_desc.isTime() ? if (op1_desc->dsc_dtype == dtype_sql_time)
((ISC_TIME_TZ*) value->vlu_desc.dsc_address)->time_zone : op1_tz_desc.makeTimeTz(&op1_time_tz);
((ISC_TIMESTAMP_TZ*) value->vlu_desc.dsc_address)->timestamp_zone; else
op1_tz_desc.makeTimestampTz(&op1_timestamp_tz);
MOV_move(tdbb, const_cast<dsc*>(op1_desc), &op1_tz_desc);
op1_desc = &op1_tz_desc;
} }
else if (op2_is_tz)
if ((op2_desc->dsc_dtype == dtype_sql_time || op2_desc->dsc_dtype == dtype_timestamp) &&
op1_desc->isDateTime() && op1_tz.specified)
{ {
tz2 = desc->isTime() ? if (op2_desc->dsc_dtype == dtype_sql_time)
((ISC_TIME_TZ*) desc->dsc_address)->time_zone : op2_tz_desc.makeTimeTz(&op2_time_tz);
((ISC_TIMESTAMP_TZ*) desc->dsc_address)->timestamp_zone; else
op2_tz_desc.makeTimestampTz(&op2_timestamp_tz);
MOV_move(tdbb, const_cast<dsc*>(op2_desc), &op2_tz_desc);
op2_desc = &op2_tz_desc;
} }
SINT64 d1, d2; SINT64 d1, d2;
@ -2782,24 +2795,24 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
// Operand 1 is Value -- Operand 2 is desc // Operand 1 is Value -- Operand 2 is desc
if (value->vlu_desc.dsc_dtype == dtype_sql_date) if (op1_desc->dsc_dtype == dtype_sql_date)
{ {
// DATE + TIME // DATE + TIME
if (desc->isTime() && blrOp == blr_add) if (op2_desc->isTime() && blrOp == blr_add)
{ {
value->vlu_misc.vlu_timestamp_tz.timestamp_date = value->vlu_misc.vlu_sql_date; value->vlu_misc.vlu_timestamp_tz.timestamp_date = *(GDS_DATE*) op1_desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_time = *(GDS_TIME*) desc->dsc_address; value->vlu_misc.vlu_timestamp_tz.timestamp_time = *(GDS_TIME*) op2_desc->dsc_address;
} }
else else
ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycan_add_timetodate)); ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycan_add_timetodate));
} }
else if (desc->dsc_dtype == dtype_sql_date) else if (op2_desc->dsc_dtype == dtype_sql_date)
{ {
// TIME + DATE // TIME + DATE
if (value->vlu_desc.isTime() && blrOp == blr_add) if (op1_desc->isTime() && blrOp == blr_add)
{ {
value->vlu_misc.vlu_timestamp_tz.timestamp_time = value->vlu_misc.vlu_sql_time; value->vlu_misc.vlu_timestamp_tz.timestamp_time = *(GDS_TIME*) op1_desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_date = *(GDS_DATE*) desc->dsc_address; value->vlu_misc.vlu_timestamp_tz.timestamp_date = *(GDS_DATE*) op2_desc->dsc_address;
} }
else else
ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycan_add_datetotime)); ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycan_add_datetotime));
@ -2821,7 +2834,7 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
to use some form of date arithmetic */ to use some form of date arithmetic */
if (blrOp == blr_subtract && if (blrOp == blr_subtract &&
(desc->isTimeStamp() || DTYPE_IS_TEXT(desc->dsc_dtype))) (op2_desc->isTimeStamp() || DTYPE_IS_TEXT(op2_desc->dsc_dtype)))
{ {
/* Handle cases of /* Handle cases of
<string> - <string> <string> - <string>
@ -2832,14 +2845,11 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
// If the first operand couldn't represent a timestamp, bomb out // If the first operand couldn't represent a timestamp, bomb out
if (!(value->vlu_desc.isTimeStamp() || if (!(op1_desc->isTimeStamp() || DTYPE_IS_TEXT(op1_desc->dsc_dtype)))
DTYPE_IS_TEXT(value->vlu_desc.dsc_dtype)))
{
ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycansub_tstampfromtstamp)); ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycansub_tstampfromtstamp));
}
d1 = getTimeStampToIscTicks(&value->vlu_desc, true); d1 = getTimeStampToIscTicks(tdbb, op1_desc);
d2 = getTimeStampToIscTicks(desc, true); d2 = getTimeStampToIscTicks(tdbb, op2_desc);
d2 = d1 - d2; d2 = d1 - d2;
@ -2898,10 +2908,10 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
a timestamp */ a timestamp */
// Coerce operand1 to a count of microseconds // Coerce operand1 to a count of microseconds
bool op1_is_timestamp = value->vlu_desc.isTimeStamp() || DTYPE_IS_TEXT(value->vlu_desc.dsc_dtype); bool op1_is_timestamp = op1_desc->isTimeStamp() || DTYPE_IS_TEXT(op1_desc->dsc_dtype);
// Coerce operand2 to a count of microseconds // Coerce operand2 to a count of microseconds
bool op2_is_timestamp = desc->isTimeStamp() || DTYPE_IS_TEXT(desc->dsc_dtype); bool op2_is_timestamp = op2_desc->isTimeStamp() || DTYPE_IS_TEXT(op2_desc->dsc_dtype);
// Exactly one of the operands must be a timestamp or // Exactly one of the operands must be a timestamp or
// convertable into a timestamp, otherwise it's one of // convertable into a timestamp, otherwise it's one of
@ -2915,15 +2925,15 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
if (op1_is_timestamp) if (op1_is_timestamp)
{ {
d1 = getTimeStampToIscTicks(&value->vlu_desc, false); d1 = getTimeStampToIscTicks(tdbb, op1_desc);
d2 = getDayFraction(desc); d2 = getDayFraction(op2_desc);
} }
else else
{ {
fb_assert(blrOp == blr_add); fb_assert(blrOp == blr_add);
fb_assert(op2_is_timestamp); fb_assert(op2_is_timestamp);
d1 = getDayFraction(&value->vlu_desc); d1 = getDayFraction(op1_desc);
d2 = getTimeStampToIscTicks(desc, false); d2 = getTimeStampToIscTicks(tdbb, op2_desc);
} }
// Perform the operation // Perform the operation
@ -2957,18 +2967,18 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
fb_assert(value->vlu_misc.vlu_timestamp_tz.timestamp_time >= 0 && fb_assert(value->vlu_misc.vlu_timestamp_tz.timestamp_time >= 0 &&
value->vlu_misc.vlu_timestamp_tz.timestamp_time < ISC_TICKS_PER_DAY); value->vlu_misc.vlu_timestamp_tz.timestamp_time < ISC_TICKS_PER_DAY);
fb_assert(!(op1_is_tz && op2_is_tz)); fb_assert(!(op1_tz.specified && op2_tz.specified));
result->dsc_dtype = op1_is_tz || op2_is_tz ? dtype_timestamp_tz : dtype_timestamp; result->dsc_dtype = op1_tz.specified || op2_tz.specified ? dtype_timestamp_tz : dtype_timestamp;
result->dsc_length = type_lengths[result->dsc_dtype]; result->dsc_length = type_lengths[result->dsc_dtype];
result->dsc_scale = 0; result->dsc_scale = 0;
result->dsc_sub_type = 0; result->dsc_sub_type = 0;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_timestamp_tz; result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_timestamp_tz;
if (op1_is_tz) if (op1_tz.specified)
((ISC_TIMESTAMP_TZ*) result->dsc_address)->timestamp_zone = tz1; value->vlu_misc.vlu_timestamp_tz.timestamp_zone = op1_tz.value;
else if (op2_is_tz) else if (op2_tz.specified)
((ISC_TIMESTAMP_TZ*) result->dsc_address)->timestamp_zone = tz2; value->vlu_misc.vlu_timestamp_tz.timestamp_zone = op2_tz.value;
return result; return result;
} }
@ -3183,31 +3193,15 @@ dsc* AtNode::execute(thread_db* tdbb, jrd_req* request) const
if (dateTimeDesc->isTimeStamp()) if (dateTimeDesc->isTimeStamp())
{ {
ISC_TIMESTAMP_TZ timeStampTz;
dsc timeStampTzDesc;
timeStampTzDesc.makeTimestampTz(&timeStampTz);
MOV_move(tdbb, dateTimeDesc, &timeStampTzDesc);
ISC_TIMESTAMP timeStamp = TimeZoneUtil::timeStampTzAtZone(timeStampTz, zone);
timeStampTz.timestamp_date = timeStamp.timestamp_date;
timeStampTz.timestamp_time = timeStamp.timestamp_time;
timeStampTz.timestamp_zone = zone;
impure->vlu_desc.makeTimestampTz(&impure->vlu_misc.vlu_timestamp_tz); impure->vlu_desc.makeTimestampTz(&impure->vlu_misc.vlu_timestamp_tz);
MOV_move(tdbb, &timeStampTzDesc, &impure->vlu_desc); MOV_move(tdbb, dateTimeDesc, &impure->vlu_desc);
impure->vlu_misc.vlu_timestamp_tz.timestamp_zone = zone;
} }
else if (dateTimeDesc->isTime()) else if (dateTimeDesc->isTime())
{ {
ISC_TIME_TZ timeTz;
dsc timeTzDesc;
timeTzDesc.makeTimeTz(&timeTz);
MOV_move(tdbb, dateTimeDesc, &timeTzDesc);
timeTz.time_time = TimeZoneUtil::timeTzAtZone(timeTz, zone);
timeTz.time_zone = zone;
impure->vlu_desc.makeTimeTz(&impure->vlu_misc.vlu_sql_time_tz); impure->vlu_desc.makeTimeTz(&impure->vlu_misc.vlu_sql_time_tz);
MOV_move(tdbb, &timeTzDesc, &impure->vlu_desc); MOV_move(tdbb, dateTimeDesc, &impure->vlu_desc);
impure->vlu_misc.vlu_sql_time_tz.time_zone = zone;
} }
else else
ERR_post(Arg::Gds(isc_expression_eval_err)); //// TODO: more info ERR_post(Arg::Gds(isc_expression_eval_err)); //// TODO: more info
@ -4116,7 +4110,7 @@ ValueExprNode* CurrentDateNode::pass2(thread_db* tdbb, CompilerScratch* csb)
return this; return this;
} }
dsc* CurrentDateNode::execute(thread_db* /*tdbb*/, jrd_req* request) const dsc* CurrentDateNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
@ -4125,12 +4119,19 @@ dsc* CurrentDateNode::execute(thread_db* /*tdbb*/, jrd_req* request) const
fb_assert(!request->req_timestamp.isEmpty()); fb_assert(!request->req_timestamp.isEmpty());
ISC_TIMESTAMP encTimes = request->req_timestamp.value(); ISC_TIMESTAMP encTimes = request->req_timestamp.value();
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc)); ISC_TIMESTAMP_TZ timeStampTz;
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp; timeStampTz.timestamp_date = encTimes.timestamp_date;
timeStampTz.timestamp_time = encTimes.timestamp_time;
timeStampTz.timestamp_zone = TimeZoneUtil::getSystemTimeZone();
TimeZoneUtil::localTimeStampToUtc(timeStampTz);
impure->vlu_misc.vlu_sql_date = TimeZoneUtil::timeStampTzToTimeStamp(
timeStampTz, tdbb->getAttachment()->att_current_timezone).timestamp_date;
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_dtype = dtype_sql_date; impure->vlu_desc.dsc_dtype = dtype_sql_date;
impure->vlu_desc.dsc_length = type_lengths[dtype_sql_date]; impure->vlu_desc.dsc_length = type_lengths[dtype_sql_date];
*(ULONG*) impure->vlu_desc.dsc_address = encTimes.timestamp_date; impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_date;
return &impure->vlu_desc; return &impure->vlu_desc;
} }
@ -4226,7 +4227,7 @@ ValueExprNode* CurrentTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/)
return this; return this;
} }
dsc* CurrentTimeNode::execute(thread_db* /*tdbb*/, jrd_req* request) const dsc* CurrentTimeNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
@ -4243,8 +4244,10 @@ dsc* CurrentTimeNode::execute(thread_db* /*tdbb*/, jrd_req* request) const
impure->vlu_desc.dsc_dtype = dtype_sql_time_tz; impure->vlu_desc.dsc_dtype = dtype_sql_time_tz;
impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time_tz]; impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time_tz];
((ISC_TIME_TZ*) impure->vlu_desc.dsc_address)->time_time = encTimes.timestamp_time; impure->vlu_misc.vlu_sql_time_tz.time_time = encTimes.timestamp_time;
((ISC_TIME_TZ*) impure->vlu_desc.dsc_address)->time_zone = TimeZoneUtil::getCurrent(); impure->vlu_misc.vlu_sql_time_tz.time_zone = TimeZoneUtil::getSystemTimeZone();
TimeZoneUtil::localTimeToUtc(impure->vlu_misc.vlu_sql_time_tz);
impure->vlu_misc.vlu_sql_time_tz.time_zone = tdbb->getAttachment()->att_current_timezone;
return &impure->vlu_desc; return &impure->vlu_desc;
} }
@ -4341,7 +4344,7 @@ ValueExprNode* CurrentTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch
return this; return this;
} }
dsc* CurrentTimeStampNode::execute(thread_db* /*tdbb*/, jrd_req* request) const dsc* CurrentTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
@ -4358,9 +4361,11 @@ dsc* CurrentTimeStampNode::execute(thread_db* /*tdbb*/, jrd_req* request) const
impure->vlu_desc.dsc_dtype = dtype_timestamp_tz; impure->vlu_desc.dsc_dtype = dtype_timestamp_tz;
impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp_tz]; impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp_tz];
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_date = encTimes.timestamp_date; impure->vlu_misc.vlu_timestamp_tz.timestamp_date = encTimes.timestamp_date;
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_time = encTimes.timestamp_time; impure->vlu_misc.vlu_timestamp_tz.timestamp_time = encTimes.timestamp_time;
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_zone = TimeZoneUtil::getCurrent(); impure->vlu_misc.vlu_timestamp_tz.timestamp_zone = TimeZoneUtil::getSystemTimeZone();
TimeZoneUtil::localTimeStampToUtc(impure->vlu_misc.vlu_timestamp_tz);
impure->vlu_misc.vlu_timestamp_tz.timestamp_zone = tdbb->getAttachment()->att_current_timezone;
return &impure->vlu_desc; return &impure->vlu_desc;
} }
@ -5254,7 +5259,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_week: case blr_extract_week:
if (!nodeIs<NullNode>(sub1) && if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_date && sub1->nodDesc.dsc_dtype != dtype_sql_date &&
sub1->nodDesc.dsc_dtype != dtype_timestamp) !sub1->nodDesc.isTimeStamp())
{ {
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) << ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch)); Arg::Gds(isc_extract_input_mismatch));
@ -5266,8 +5271,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_second: case blr_extract_second:
case blr_extract_millisecond: case blr_extract_millisecond:
if (!nodeIs<NullNode>(sub1) && if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_time && !sub1->nodDesc.isTime() &&
sub1->nodDesc.dsc_dtype != dtype_timestamp) !sub1->nodDesc.isTimeStamp())
{ {
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) << ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch)); Arg::Gds(isc_extract_input_mismatch));
@ -5277,8 +5282,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_timezone_hour: case blr_extract_timezone_hour:
case blr_extract_timezone_minute: case blr_extract_timezone_minute:
if (!nodeIs<NullNode>(sub1) && if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_time_tz && !sub1->nodDesc.isTime() &&
sub1->nodDesc.dsc_dtype != dtype_timestamp_tz) !sub1->nodDesc.isTimeStamp())
{ {
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) << ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch)); Arg::Gds(isc_extract_input_mismatch));
@ -5400,7 +5405,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
const dsc* value = EVL_expr(tdbb, request, arg); dsc* value = EVL_expr(tdbb, request, arg);
if (!value || (request->req_flags & req_null)) if (!value || (request->req_flags & req_null))
return NULL; return NULL;
@ -5414,7 +5419,6 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
switch (value->dsc_dtype) switch (value->dsc_dtype)
{ {
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz:
switch (blrSubOp) switch (blrSubOp)
{ {
case blr_extract_hour: case blr_extract_hour:
@ -5427,14 +5431,35 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_timezone_hour: case blr_extract_timezone_hour:
case blr_extract_timezone_minute: case blr_extract_timezone_minute:
if (value->dsc_dtype == dtype_sql_time_tz)
{ {
dsc tempDsc;
tempDsc.makeTimestampTz(&timeStampTz);
MOV_move(tdbb, value, &tempDsc);
break;
}
default:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_time));
}
break;
case dtype_sql_time_tz:
switch (blrSubOp)
{
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) value->dsc_address, &times, &fractions);
break;
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
timeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date; //// FIXME: ??? timeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date; //// FIXME: ???
timeStampTz.timestamp_time = ((ISC_TIME_TZ*) value->dsc_address)->time_time; timeStampTz.timestamp_time = ((ISC_TIME_TZ*) value->dsc_address)->time_time;
timeStampTz.timestamp_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone; timeStampTz.timestamp_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone;
break; break;
}
// else fall into
default: default:
ERR_post(Arg::Gds(isc_expression_eval_err) << ERR_post(Arg::Gds(isc_expression_eval_err) <<
@ -5465,9 +5490,12 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
case blr_extract_timezone_hour: case blr_extract_timezone_hour:
case blr_extract_timezone_minute: case blr_extract_timezone_minute:
ERR_post(Arg::Gds(isc_expression_eval_err) << {
Arg::Gds(isc_invalid_extractpart_date)); dsc tempDsc;
tempDsc.makeTimestampTz(&timeStampTz);
MOV_move(tdbb, value, &tempDsc);
break; break;
}
default: default:
TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) value->dsc_address, &times, &fractions); TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) value->dsc_address, &times, &fractions);
@ -5481,6 +5509,9 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_timezone_minute: case blr_extract_timezone_minute:
timeStampTz = *(ISC_TIMESTAMP_TZ*) value->dsc_address; timeStampTz = *(ISC_TIMESTAMP_TZ*) value->dsc_address;
break; break;
default:
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, &times, &fractions);
} }
break; break;
@ -7898,7 +7929,7 @@ ValueExprNode* LocalTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/)
return this; return this;
} }
dsc* LocalTimeNode::execute(thread_db* /*tdbb*/, jrd_req* request) const dsc* LocalTimeNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
@ -7907,14 +7938,19 @@ dsc* LocalTimeNode::execute(thread_db* /*tdbb*/, jrd_req* request) const
fb_assert(!request->req_timestamp.isEmpty()); fb_assert(!request->req_timestamp.isEmpty());
ISC_TIMESTAMP encTimes = request->req_timestamp.value(); ISC_TIMESTAMP encTimes = request->req_timestamp.value();
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_time;
TimeStamp::round_time(encTimes.timestamp_time, precision); TimeStamp::round_time(encTimes.timestamp_time, precision);
ISC_TIME_TZ timeTz;
timeTz.time_time = encTimes.timestamp_time;
timeTz.time_zone = TimeZoneUtil::getSystemTimeZone();
TimeZoneUtil::localTimeToUtc(timeTz);
impure->vlu_misc.vlu_sql_time = TimeZoneUtil::timeTzToTime(timeTz, tdbb->getAttachment()->att_current_timezone);
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_dtype = dtype_sql_time; impure->vlu_desc.dsc_dtype = dtype_sql_time;
impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time]; impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time];
*(ULONG*) impure->vlu_desc.dsc_address = encTimes.timestamp_time; impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_time;
return &impure->vlu_desc; return &impure->vlu_desc;
} }
@ -7997,7 +8033,7 @@ ValueExprNode* LocalTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/
return this; return this;
} }
dsc* LocalTimeStampNode::execute(thread_db* /*tdbb*/, jrd_req* request) const dsc* LocalTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const
{ {
impure_value* const impure = request->getImpure<impure_value>(impureOffset); impure_value* const impure = request->getImpure<impure_value>(impureOffset);
request->req_flags &= ~req_null; request->req_flags &= ~req_null;
@ -8006,14 +8042,21 @@ dsc* LocalTimeStampNode::execute(thread_db* /*tdbb*/, jrd_req* request) const
fb_assert(!request->req_timestamp.isEmpty()); fb_assert(!request->req_timestamp.isEmpty());
ISC_TIMESTAMP encTimes = request->req_timestamp.value(); ISC_TIMESTAMP encTimes = request->req_timestamp.value();
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp;
TimeStamp::round_time(encTimes.timestamp_time, precision); TimeStamp::round_time(encTimes.timestamp_time, precision);
ISC_TIMESTAMP_TZ timeStampTz;
timeStampTz.timestamp_date = encTimes.timestamp_date;
timeStampTz.timestamp_time = encTimes.timestamp_time;
timeStampTz.timestamp_zone = TimeZoneUtil::getSystemTimeZone();
TimeZoneUtil::localTimeStampToUtc(timeStampTz);
impure->vlu_misc.vlu_timestamp = TimeZoneUtil::timeStampTzToTimeStamp(
timeStampTz, tdbb->getAttachment()->att_current_timezone);
memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc));
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp;
impure->vlu_desc.dsc_dtype = dtype_timestamp; impure->vlu_desc.dsc_dtype = dtype_timestamp;
impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp]; impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp];
*((ISC_TIMESTAMP*) impure->vlu_desc.dsc_address) = encTimes;
return &impure->vlu_desc; return &impure->vlu_desc;
} }
@ -11179,7 +11222,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, jrd_req* request) const
// impure will stay long, and the first add() will // impure will stay long, and the first add() will
// set the correct scale; if it is approximate numeric, // set the correct scale; if it is approximate numeric,
// the first add() will convert impure to double. // the first add() will convert impure to double.
ArithmeticNode::add(desc, impure, this, blr_add); ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
++count; ++count;
} }
@ -13395,32 +13438,22 @@ static SINT64 getDayFraction(const dsc* d)
// date and time in MJD time arithmetic. // date and time in MJD time arithmetic.
// ISC_TICKS or isc_ticks are actually deci - milli seconds or tenthousandth of seconds per day. // ISC_TICKS or isc_ticks are actually deci - milli seconds or tenthousandth of seconds per day.
// This is derived from the ISC_TIME_SECONDS_PRECISION. // This is derived from the ISC_TIME_SECONDS_PRECISION.
static SINT64 getTimeStampToIscTicks(const dsc* d, bool utc) static SINT64 getTimeStampToIscTicks(thread_db* tdbb, const dsc* d)
{ {
thread_db* tdbb = JRD_get_thread_data();
dsc result; dsc result;
ISC_TIMESTAMP_TZ result_timestamp; ISC_TIMESTAMP_TZ result_timestamp;
result.dsc_dtype = dtype_timestamp_tz; result.dsc_dtype = d->isDateTimeTz() ? dtype_timestamp_tz : dtype_timestamp;
result.dsc_scale = 0; result.dsc_scale = 0;
result.dsc_flags = 0; result.dsc_flags = 0;
result.dsc_sub_type = 0; result.dsc_sub_type = 0;
result.dsc_length = sizeof(result_timestamp); result.dsc_length = d->isDateTimeTz() ? sizeof(ISC_TIMESTAMP_TZ) : sizeof(ISC_TIMESTAMP);
result.dsc_address = reinterpret_cast<UCHAR*>(&result_timestamp); result.dsc_address = reinterpret_cast<UCHAR*>(&result_timestamp);
CVT_move(d, &result, tdbb->getAttachment()->att_dec_status); CVT_move(d, &result, tdbb->getAttachment()->att_dec_status);
SINT64 delta = 0; SINT64 delta = 0;
if (utc)
{
int tzSign;
unsigned tzh, tzm;
TimeZoneUtil::extractOffset(result_timestamp, &tzSign, &tzh, &tzm);
delta = tzSign * int(tzh * 60 + tzm) * 60 * ISC_TIME_SECONDS_PRECISION;
}
return ((SINT64) result_timestamp.timestamp_date) * ISC_TICKS_PER_DAY + return ((SINT64) result_timestamp.timestamp_date) * ISC_TICKS_PER_DAY +
(SINT64) result_timestamp.timestamp_time - delta; (SINT64) result_timestamp.timestamp_time - delta;
} }

View File

@ -93,17 +93,19 @@ public:
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const; virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
// add and add2 are used in somewhat obscure way in aggregation. // add and add2 are used in somewhat obscure way in aggregation.
static dsc* add(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp); static dsc* add(thread_db* tdbb, const dsc* desc, impure_value* value, const ValueExprNode* node,
static dsc* add2(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp); const UCHAR blrOp);
static dsc* add2(thread_db* tdbb, const dsc* desc, impure_value* value, const ValueExprNode* node,
const UCHAR blrOp);
private: private:
dsc* multiply(const dsc* desc, impure_value* value) const; dsc* multiply(const dsc* desc, impure_value* value) const;
dsc* multiply2(const dsc* desc, impure_value* value) const; dsc* multiply2(const dsc* desc, impure_value* value) const;
dsc* divide2(const dsc* desc, impure_value* value) const; dsc* divide2(const dsc* desc, impure_value* value) const;
dsc* addDateTime(const dsc* desc, impure_value* value) const; dsc* addDateTime(thread_db* tdbb, const dsc* desc, impure_value* value) const;
dsc* addSqlDate(const dsc* desc, impure_value* value) const; dsc* addSqlDate(const dsc* desc, impure_value* value) const;
dsc* addSqlTime(const dsc* desc, impure_value* value) const; dsc* addSqlTime(thread_db* tdbb, const dsc* desc, impure_value* value) const;
dsc* addTimeStamp(const dsc* desc, impure_value* value) const; dsc* addTimeStamp(thread_db* tdbb, const dsc* desc, impure_value* value) const;
private: private:
void makeDialect1(dsc* desc, dsc& desc1, dsc& desc2); void makeDialect1(dsc* desc, dsc& desc1, dsc& desc2);

View File

@ -145,20 +145,22 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag)
{ {
// Setup the constant's descriptor // Setup the constant's descriptor
EXPECT_DATETIME expect; EXPECT_DATETIME expect1, expect2;
switch (numeric_flag) switch (numeric_flag)
{ {
case CONSTANT_DATE: case CONSTANT_DATE:
expect = expect_sql_date; expect1 = expect2 = expect_sql_date;
break; break;
case CONSTANT_TIME: case CONSTANT_TIME:
expect = expect_sql_time_tz; expect1 = expect_sql_time_tz;
expect2 = expect_sql_time;
break; break;
case CONSTANT_TIMESTAMP: case CONSTANT_TIMESTAMP:
expect = expect_timestamp_tz; expect1 = expect_timestamp_tz;
expect2 = expect_timestamp;
break; break;
default: default:
@ -180,7 +182,10 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag)
ISC_TIMESTAMP_TZ ts; ISC_TIMESTAMP_TZ ts;
bool tz; bool tz;
CVT_string_to_datetime(&tmp, &ts, &tz, expect, false, &EngineCallbacks::instance); CVT_string_to_datetime(&tmp, &ts, &tz, expect1, false, &EngineCallbacks::instance);
if (!tz && expect1 != expect2)
CVT_string_to_datetime(&tmp, &ts, &tz, expect2, false, &EngineCallbacks::instance);
switch (numeric_flag) switch (numeric_flag)
{ {

View File

@ -1071,6 +1071,7 @@ interface Util : Versioned
void decodeTime(ISC_TIME time, uint* hours, uint* minutes, uint* seconds, uint* fractions); void decodeTime(ISC_TIME time, uint* hours, uint* minutes, uint* seconds, uint* fractions);
ISC_DATE encodeDate(uint year, uint month, uint day); ISC_DATE encodeDate(uint year, uint month, uint day);
ISC_TIME encodeTime(uint hours, uint minutes, uint seconds, uint fractions); ISC_TIME encodeTime(uint hours, uint minutes, uint seconds, uint fractions);
//// TODO: TZ functions
uint formatStatus(string buffer, uint bufferSize, Status status); uint formatStatus(string buffer, uint bufferSize, Status status);
uint getClientVersion(); // Returns major * 256 + minor uint getClientVersion(); // Returns major * 256 + minor
XpbBuilder getXpbBuilder(Status status, uint kind, const uchar* buf, uint len); XpbBuilder getXpbBuilder(Status status, uint kind, const uchar* buf, uint len);

View File

@ -157,9 +157,9 @@ const int FLOAT_LEN = 14; // -1.2345678E+38
const int DOUBLE_LEN = 23; // -1.234567890123456E+300 const int DOUBLE_LEN = 23; // -1.234567890123456E+300
const int DATE_LEN = 11; // 11 for date only const int DATE_LEN = 11; // 11 for date only
const int DATETIME_LEN = 25; // 25 for date-time const int DATETIME_LEN = 25; // 25 for date-time
const int DATETIME_TZ_LEN = 31; // 31 for date-time-tz const int DATETIME_TZ_LEN = DATETIME_LEN - 1 + 1 + TimeZoneUtil::MAX_LEN; // DATETIME_LEN should be 24
const int TIME_ONLY_LEN = 13; // 13 for time only const int TIME_ONLY_LEN = 13; // 13 for time only
const int TIME_TZ_ONLY_LEN = 20; // 20 for time-tz only const int TIME_TZ_ONLY_LEN = TIME_ONLY_LEN + 1 + TimeZoneUtil::MAX_LEN;
const int DATE_ONLY_LEN = 11; const int DATE_ONLY_LEN = 11;
const int BOOLEAN_LEN = 7; // <false> const int BOOLEAN_LEN = 7; // <false>
const int UNKNOWN_LEN = 20; // Unknown type: %d const int UNKNOWN_LEN = 20; // Unknown type: %d
@ -7066,7 +7066,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
* *
**************************************/ **************************************/
const char* convErr = "Conversion error"; const char* convErr = "Conversion error";
TEXT d[32]; TEXT d[64];
TEXT* p = *s; TEXT* p = *s;
*p = '\0'; *p = '\0';
@ -7403,7 +7403,17 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
case SQL_TIMESTAMP: case SQL_TIMESTAMP:
case SQL_TIMESTAMP_TZ: case SQL_TIMESTAMP_TZ:
{
char timeZone[TimeZoneUtil::MAX_SIZE];
ULONG fractions;
if (dtype == SQL_TIMESTAMP_TZ)
isc_decode_timestamp_tz(var->value.asDateTimeTz, &times, &fractions, timeZone, sizeof(timeZone));
else
{
isc_decode_timestamp(var->value.asDateTime, &times); isc_decode_timestamp(var->value.asDateTime, &times);
fractions = ((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION;
}
if (isqlGlob.SQL_dialect > SQL_DIALECT_V5) if (isqlGlob.SQL_dialect > SQL_DIALECT_V5)
{ {
@ -7411,7 +7421,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
times.tm_year + 1900, (times.tm_mon + 1), times.tm_year + 1900, (times.tm_mon + 1),
times.tm_mday, times.tm_hour, times.tm_min, times.tm_mday, times.tm_hour, times.tm_min,
times.tm_sec, times.tm_sec,
((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION); fractions);
} }
else else
{ {
@ -7420,7 +7430,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
times.tm_mday, alpha_months[times.tm_mon], times.tm_mday, alpha_months[times.tm_mon],
times.tm_year + 1900, times.tm_hour, times.tm_min, times.tm_year + 1900, times.tm_hour, times.tm_min,
times.tm_sec, times.tm_sec,
((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION); fractions);
else else
sprintf(d, "%2d-%s-%4d", times.tm_mday, sprintf(d, "%2d-%s-%4d", times.tm_mday,
alpha_months[times.tm_mon], times.tm_year + 1900); alpha_months[times.tm_mon], times.tm_year + 1900);
@ -7430,7 +7440,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
{ {
size_t len = strlen(d); size_t len = strlen(d);
strcat(d + len, " "); strcat(d + len, " ");
TimeZoneUtil::format(d + len + 1, sizeof(d) - (len + 1), var->value.asDateTimeTz->timestamp_zone); strcat(d + len + 1, timeZone);
} }
sprintf(p, "%-*.*s ", length, length, d); sprintf(p, "%-*.*s ", length, length, d);
@ -7439,19 +7449,31 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
isqlGlob.printf("%s%s", d, NEWLINE); isqlGlob.printf("%s%s", d, NEWLINE);
break; break;
}
case SQL_TYPE_TIME: case SQL_TYPE_TIME:
case SQL_TIME_TZ: case SQL_TIME_TZ:
{
char timeZone[TimeZoneUtil::MAX_SIZE];
ULONG fractions;
if (dtype == SQL_TIME_TZ)
isc_decode_sql_time_tz(var->value.asTimeTz, &times, &fractions, timeZone, sizeof(timeZone));
else
{
isc_decode_sql_time(var->value.asTime, &times); isc_decode_sql_time(var->value.asTime, &times);
fractions = (*var->value.asTime) % ISC_TIME_SECONDS_PRECISION;
}
sprintf(d, "%2.2d:%2.2d:%2.2d.%4.4" ULONGFORMAT, sprintf(d, "%2.2d:%2.2d:%2.2d.%4.4" ULONGFORMAT,
times.tm_hour, times.tm_min, times.tm_sec, times.tm_hour, times.tm_min, times.tm_sec,
(*var->value.asTime) % ISC_TIME_SECONDS_PRECISION); fractions);
if (dtype == SQL_TIME_TZ) if (dtype == SQL_TIME_TZ)
{ {
size_t len = strlen(d); size_t len = strlen(d);
strcat(d + len, " "); strcat(d + len, " ");
TimeZoneUtil::format(d + len + 1, sizeof(d) - (len + 1), var->value.asTimeTz->time_zone); strcat(d + len + 1, timeZone);
} }
sprintf(p, "%-*.*s ", length, length, d); sprintf(p, "%-*.*s ", length, length, d);
@ -7460,6 +7482,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
isqlGlob.printf("%s%s", d, NEWLINE); isqlGlob.printf("%s%s", d, NEWLINE);
break; break;
}
case SQL_TYPE_DATE: case SQL_TYPE_DATE:
isc_decode_sql_date(var->value.asDate, &times); isc_decode_sql_date(var->value.asDate, &times);

View File

@ -228,7 +228,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_ext_parent(NULL), att_ext_parent(NULL),
att_ext_call_depth(0), att_ext_call_depth(0),
att_trace_manager(FB_NEW_POOL(*att_pool) TraceManager(this)), att_trace_manager(FB_NEW_POOL(*att_pool) TraceManager(this)),
att_original_timezone(TimeZoneUtil::getCurrent()), att_original_timezone(TimeZoneUtil::getSystemTimeZone()),
att_current_timezone(att_original_timezone), att_current_timezone(att_original_timezone),
att_utility(UTIL_NONE), att_utility(UTIL_NONE),
att_procedures(*pool), att_procedures(*pool),

View File

@ -29,6 +29,7 @@
*/ */
#include "firebird.h" #include "firebird.h"
#include "../common/TimeZoneUtil.h"
#include "../common/classes/VaryStr.h" #include "../common/classes/VaryStr.h"
#include "../common/classes/Hash.h" #include "../common/classes/Hash.h"
#include "../jrd/SysFunction.h" #include "../jrd/SysFunction.h"
@ -527,7 +528,7 @@ void setParamsDateAdd(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc*
} }
if (argsCount >= 3 && args[2]->isUnknown()) if (argsCount >= 3 && args[2]->isUnknown())
args[2]->makeTimestamp(); args[2]->makeTimestamp(); //// TODO:
} }
@ -553,7 +554,7 @@ void setParamsFirstLastDay(DataTypeUtilBase*, const SysFunction*, int argsCount,
if (argsCount >= 2) if (argsCount >= 2)
{ {
if (args[1]->isUnknown()) if (args[1]->isUnknown())
args[1]->makeTimestamp(); args[1]->makeTimestamp(); //// TODO:
} }
} }
@ -986,8 +987,13 @@ void makeFirstLastDayResult(DataTypeUtilBase*, const SysFunction*, dsc* result,
result->makeDate(); result->makeDate();
if (argsCount >= 2 && args[1]->dsc_dtype == dtype_timestamp) if (argsCount >= 2)
{
if (args[1]->dsc_dtype == dtype_timestamp)
result->makeTimestamp(); result->makeTimestamp();
else if (args[1]->dsc_dtype == dtype_timestamp_tz)
result->makeTimestampTz();
}
result->setNullable(isNullable); result->setNullable(isNullable);
} }
@ -1938,6 +1944,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr
switch (valueDsc->dsc_dtype) switch (valueDsc->dsc_dtype)
{ {
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz:
timestamp.value().timestamp_time = *(GDS_TIME*) valueDsc->dsc_address; timestamp.value().timestamp_time = *(GDS_TIME*) valueDsc->dsc_address;
timestamp.value().timestamp_date = timestamp.value().timestamp_date =
(TimeStamp::MAX_DATE - TimeStamp::MIN_DATE) / 2 + TimeStamp::MIN_DATE; (TimeStamp::MAX_DATE - TimeStamp::MIN_DATE) / 2 + TimeStamp::MIN_DATE;
@ -1968,6 +1975,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr
break; break;
case dtype_timestamp: case dtype_timestamp:
case dtype_timestamp_tz:
timestamp.value() = *(GDS_TIMESTAMP*) valueDsc->dsc_address; timestamp.value() = *(GDS_TIMESTAMP*) valueDsc->dsc_address;
break; break;
@ -2097,6 +2105,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr
switch (impure->vlu_desc.dsc_dtype) switch (impure->vlu_desc.dsc_dtype)
{ {
case dtype_sql_time: case dtype_sql_time:
case dtype_sql_time_tz:
impure->vlu_misc.vlu_sql_time = timestamp.value().timestamp_time; impure->vlu_misc.vlu_sql_time = timestamp.value().timestamp_time;
break; break;
@ -2105,6 +2114,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr
break; break;
case dtype_timestamp: case dtype_timestamp:
case dtype_timestamp_tz:
impure->vlu_misc.vlu_timestamp = timestamp.value(); impure->vlu_misc.vlu_timestamp = timestamp.value();
break; break;
@ -2118,6 +2128,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr
} }
//// FIXME:
dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueArray& args,
impure_value* impure) impure_value* impure)
{ {
@ -2400,6 +2411,10 @@ dsc* evlFirstLastDay(thread_db* tdbb, const SysFunction* function, const NestVal
timestamp.decode(&times, &fractions); timestamp.decode(&times, &fractions);
break; break;
case dtype_timestamp_tz:
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, &times, &fractions);
break;
default: default:
status_exception::raise( status_exception::raise(
Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_expression_eval_err) <<
@ -2478,6 +2493,14 @@ dsc* evlFirstLastDay(thread_db* tdbb, const SysFunction* function, const NestVal
case dtype_timestamp: case dtype_timestamp:
impure->vlu_misc.vlu_timestamp = timestamp.value(); impure->vlu_misc.vlu_timestamp = timestamp.value();
break; break;
case dtype_timestamp_tz:
impure->vlu_misc.vlu_timestamp_tz.timestamp_date = timestamp.value().timestamp_date;
impure->vlu_misc.vlu_timestamp_tz.timestamp_time = timestamp.value().timestamp_time;
impure->vlu_misc.vlu_timestamp_tz.timestamp_zone =
((ISC_TIMESTAMP_TZ*) valueDsc->dsc_address)->timestamp_zone;
TimeZoneUtil::localTimeStampToUtc(impure->vlu_misc.vlu_timestamp_tz);
break;
} }
return &impure->vlu_desc; return &impure->vlu_desc;

View File

@ -2602,8 +2602,7 @@ static void compress(thread_db* tdbb,
} }
else if (itype == idx_sql_time_tz) else if (itype == idx_sql_time_tz)
{ {
ISC_TIME_TZ timeTz = MOV_get_sql_time_tz(desc); temp.temp_ulong = MOV_get_sql_time_tz(desc).time_time;
temp.temp_ulong = TimeZoneUtil::timeTzAtZone(timeTz, TimeZoneUtil::UTC_ZONE);
temp_copy_length = sizeof(ULONG); temp_copy_length = sizeof(ULONG);
temp_is_negative = false; temp_is_negative = false;
@ -2627,10 +2626,10 @@ static void compress(thread_db* tdbb,
else if (desc->dsc_dtype == dtype_timestamp_tz) else if (desc->dsc_dtype == dtype_timestamp_tz)
{ {
ISC_TIMESTAMP_TZ timestampTz = MOV_get_timestamp_tz(desc); ISC_TIMESTAMP_TZ timestampTz = MOV_get_timestamp_tz(desc);
ISC_TIMESTAMP timestamp = TimeZoneUtil::timeStampTzAtZone(timestampTz, TimeZoneUtil::UTC_ZONE); ISC_TIMESTAMP* timestamp = (ISC_TIMESTAMP*) &timestampTz;
dsc descTimestamp; dsc descTimestamp;
descTimestamp.makeTimestamp(&timestamp); descTimestamp.makeTimestamp(timestamp);
temp.temp_double = MOV_date_to_double(&descTimestamp); temp.temp_double = MOV_date_to_double(&descTimestamp);
temp_is_negative = (temp.temp_double < 0); temp_is_negative = (temp.temp_double < 0);

View File

@ -221,9 +221,6 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
// Handle the simple (matched) ones first // Handle the simple (matched) ones first
ISC_TIME time1, time2;
ISC_TIMESTAMP timestamp1, timestamp2;
if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale) if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale)
{ {
const UCHAR* p1 = arg1->dsc_address; const UCHAR* p1 = arg1->dsc_address;
@ -239,12 +236,6 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
return -1; return -1;
case dtype_sql_time_tz: case dtype_sql_time_tz:
time1 = TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) p1, TimeZoneUtil::UTC_ZONE);
p1 = (const UCHAR*) &time1;
time2 = TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) p2, TimeZoneUtil::UTC_ZONE);
p2 = (const UCHAR*) &time2;
// fall into
case dtype_sql_time: case dtype_sql_time:
if (*(ULONG *) p1 == *(ULONG *) p2) if (*(ULONG *) p1 == *(ULONG *) p2)
return 0; return 0;
@ -283,12 +274,6 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
} }
case dtype_timestamp_tz: case dtype_timestamp_tz:
timestamp1 = TimeZoneUtil::timeStampTzAtZone(*(ISC_TIMESTAMP_TZ*) p1, TimeZoneUtil::UTC_ZONE);
p1 = (const UCHAR*) &timestamp1;
timestamp2 = TimeZoneUtil::timeStampTzAtZone(*(ISC_TIMESTAMP_TZ*) p2, TimeZoneUtil::UTC_ZONE);
p2 = (const UCHAR*) &timestamp2;
// fall into
case dtype_timestamp: case dtype_timestamp:
if (((SLONG *) p1)[0] > ((SLONG *) p2)[0]) if (((SLONG *) p1)[0] > ((SLONG *) p2)[0])
return 1; return 1;

View File

@ -100,71 +100,6 @@ namespace
return lock.release(); return lock.release();
} }
class UtcConversor
{
public:
UtcConversor(record_param* aRpb)
: rpb(aRpb)
{
convert(rpb, -1);
}
~UtcConversor()
{
convert(rpb, 1);
}
public:
static void convert(record_param* rpb, int direction)
{
fb_assert(rpb && rpb->rpb_record && rpb->rpb_record->getFormat());
const Format* format = rpb->rpb_record->getFormat();
UCHAR* data = rpb->rpb_record->getData();
tm times = {0};
int fractions;
for (USHORT i = 0; i < format->fmt_count; ++i)
{
const dsc& desc = format->fmt_desc[i];
#if 0 //// FIXME:
switch (desc.dsc_dtype)
{
case dtype_sql_time_tz:
{
ISC_TIME_TZ* valueTz = reinterpret_cast<ISC_TIME_TZ*>(data + (IPTR) desc.dsc_address);
ISC_TIME* value = (ISC_TIME*) valueTz;
SINT64 ticks = (SINT64) *value;
ticks += valueTz->time_displacement * 60 * ISC_TIME_SECONDS_PRECISION * direction;
//// FIXME: ticks?
break;
}
case dtype_timestamp_tz:
{
ISC_TIMESTAMP_TZ* valueTz = reinterpret_cast<ISC_TIMESTAMP_TZ*>(data + (IPTR) desc.dsc_address);
ISC_TIMESTAMP* value = (ISC_TIMESTAMP*) valueTz;
SINT64 ticks = ((SINT64) value->timestamp_date) * TimeStamp::ISC_TICKS_PER_DAY +
(SINT64) value->timestamp_time;
ticks += valueTz->timestamp_displacement * 60 * ISC_TIME_SECONDS_PRECISION * direction;
//// FIXME: ticks?
break;
}
}
#endif
}
}
private:
record_param* rpb;
};
} }
@ -432,7 +367,6 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
record_param temp = *org_rpb; record_param temp = *org_rpb;
// This function is currently called only by VIO_erase and new_rpb does not have a record. // This function is currently called only by VIO_erase and new_rpb does not have a record.
///UtcConversor utcConversor(new_rpb);
fb_assert(new_rpb->rpb_length == 0); fb_assert(new_rpb->rpb_length == 0);
const Compressor dcc(*tdbb->getDefaultPool(), new_rpb->rpb_length, new_rpb->rpb_address); const Compressor dcc(*tdbb->getDefaultPool(), new_rpb->rpb_length, new_rpb->rpb_address);
@ -2148,7 +2082,6 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd:
rpb->rpb_f_line, rpb->rpb_flags); rpb->rpb_f_line, rpb->rpb_flags);
#endif #endif
UtcConversor utcConversor(rpb);
const Compressor dcc(*tdbb->getDefaultPool(), rpb->rpb_length, rpb->rpb_address); const Compressor dcc(*tdbb->getDefaultPool(), rpb->rpb_length, rpb->rpb_address);
const ULONG size = (ULONG) dcc.getPackedLength(); const ULONG size = (ULONG) dcc.getPackedLength();
@ -2374,7 +2307,6 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
CCH_MARK(tdbb, &rpb->getWindow(tdbb)); CCH_MARK(tdbb, &rpb->getWindow(tdbb));
data_page* page = (data_page*) rpb->getWindow(tdbb).win_buffer; data_page* page = (data_page*) rpb->getWindow(tdbb).win_buffer;
///UtcConversor utcConversor(rpb);
const Compressor dcc(*tdbb->getDefaultPool(), rpb->rpb_length, rpb->rpb_address); const Compressor dcc(*tdbb->getDefaultPool(), rpb->rpb_length, rpb->rpb_address);
const ULONG size = (ULONG) dcc.getPackedLength(); const ULONG size = (ULONG) dcc.getPackedLength();

View File

@ -375,9 +375,21 @@ void ISC_EXPORT isc_decode_sql_date(const ISC_DATE*,
void ISC_EXPORT isc_decode_sql_time(const ISC_TIME*, void ISC_EXPORT isc_decode_sql_time(const ISC_TIME*,
void*); void*);
void ISC_EXPORT isc_decode_sql_time_tz(const ISC_TIME_TZ*,
void*,
ISC_ULONG*,
char*,
unsigned short);
void ISC_EXPORT isc_decode_timestamp(const ISC_TIMESTAMP*, void ISC_EXPORT isc_decode_timestamp(const ISC_TIMESTAMP*,
void*); void*);
void ISC_EXPORT isc_decode_timestamp_tz(const ISC_TIMESTAMP_TZ*,
void*,
ISC_ULONG*,
char*,
unsigned short);
ISC_STATUS ISC_EXPORT isc_detach_database(ISC_STATUS *, ISC_STATUS ISC_EXPORT isc_detach_database(ISC_STATUS *,
isc_db_handle *); isc_db_handle *);

View File

@ -675,7 +675,7 @@ namespace Jrd
struct DummyAdjustFunctor struct DummyAdjustFunctor
{ {
void operator ()(impure_value* target) void operator ()(thread_db* /*tdbb*/, impure_value* /*target*/)
{ {
} }
}; };
@ -736,7 +736,7 @@ namespace Jrd
else else
{ {
EVL_make_value(tdbb, desc, target); EVL_make_value(tdbb, desc, target);
adjustFunctor(target); adjustFunctor(tdbb, target);
} }
} }
} }
@ -779,9 +779,9 @@ namespace Jrd
{ {
} }
void operator ()(impure_value* target) void operator ()(thread_db* tdbb, impure_value* target)
{ {
ArithmeticNode::add2(offsetDesc, target, arithNode, arithNode->blrOp); ArithmeticNode::add2(tdbb, offsetDesc, target, arithNode, arithNode->blrOp);
} }
const ArithmeticNode* arithNode; const ArithmeticNode* arithNode;

View File

@ -933,26 +933,10 @@ void Sort::diddleKey(UCHAR* record, bool direction)
switch (key->skd_dtype) switch (key->skd_dtype)
{ {
case SKD_sql_time_tz:
if (direction)
{
*(ISC_TIME*) p = TimeZoneUtil::timeTzAtZone(*(ISC_TIME_TZ*) p, TimeZoneUtil::UTC_ZONE);
((ISC_TIME_TZ*) p)->time_zone = TimeZoneUtil::UTC_ZONE;
}
p[3] ^= 1 << 7;
break;
case SKD_timestamp_tz:
if (direction)
{
*(ISC_TIMESTAMP*) p = TimeZoneUtil::timeStampTzAtZone(*(ISC_TIMESTAMP_TZ*) p, TimeZoneUtil::UTC_ZONE);
((ISC_TIMESTAMP_TZ*) p)->timestamp_zone = TimeZoneUtil::UTC_ZONE;
}
p[3] ^= 1 << 7;
break;
case SKD_timestamp: case SKD_timestamp:
case SKD_timestamp_tz:
case SKD_sql_time: case SKD_sql_time:
case SKD_sql_time_tz:
case SKD_sql_date: case SKD_sql_date:
p[3] ^= 1 << 7; p[3] ^= 1 << 7;
break; break;

View File

@ -47,6 +47,7 @@
#include "../yvalve/gds_proto.h" #include "../yvalve/gds_proto.h"
#include "../common/os/path_utils.h" #include "../common/os/path_utils.h"
#include "../common/dsc.h" #include "../common/dsc.h"
#include "../common/TimeZoneUtil.h"
#include "../jrd/constants.h" #include "../jrd/constants.h"
#include "../jrd/status.h" #include "../jrd/status.h"
#include "../common/os/os_utils.h" #include "../common/os/os_utils.h"
@ -133,6 +134,7 @@ const SLONG GENERIC_SQLCODE = -999;
#include "../common/classes/MsgPrint.h" #include "../common/classes/MsgPrint.h"
using Firebird::TimeStamp; using Firebird::TimeStamp;
using Firebird::TimeZoneUtil;
using Firebird::BlrReader; using Firebird::BlrReader;
// This structure is used to parse the firebird.msg file. // This structure is used to parse the firebird.msg file.
@ -481,6 +483,40 @@ void API_ROUTINE isc_decode_sql_time(const GDS_TIME* sql_time, void* times_arg)
} }
//// TODO: isc_encode_sql_time_tz
void API_ROUTINE isc_decode_sql_time_tz(const ISC_TIME_TZ* timeTz, void* timesArg, ULONG* fractions,
char* buffer, unsigned short bufferSize)
{
/**************************************
*
* i s c _ d e c o d e _ s q l _ t i m e _ t z
*
**************************************
*
* Functional description
* Convert from internal TIME-tz format to UNIX time structure.
*
**************************************/
tm* const times = static_cast<struct tm*>(timesArg);
try
{
int intFractions;
TimeZoneUtil::decodeTime(*timeTz, times, &intFractions);
if (fractions)
*fractions = (ULONG) intFractions;
if (buffer)
TimeZoneUtil::format(buffer, bufferSize, timeTz->time_zone);
}
catch (const Firebird::Exception&)
{
//// FIXME:
}
}
void API_ROUTINE isc_decode_timestamp(const GDS_TIMESTAMP* date, void* times_arg) void API_ROUTINE isc_decode_timestamp(const GDS_TIMESTAMP* date, void* times_arg)
{ {
/************************************** /**************************************
@ -501,6 +537,43 @@ void API_ROUTINE isc_decode_timestamp(const GDS_TIMESTAMP* date, void* times_arg
} }
//// TODO: isc_encode_timestamp_tz
void API_ROUTINE isc_decode_timestamp_tz(const ISC_TIMESTAMP_TZ* timeStampTz, void* timesArg, ULONG* fractions,
char* buffer, unsigned short bufferSize)
{
/**************************************
*
* i s c _ d e c o d e _ t i m e s t a m p _ t z
*
**************************************
*
* Functional description
* Convert from internal timestamp-tz format to UNIX time structure.
*
* Note: This routine is intended only for public API use. Engine itself and
* utilities should be using TimeStamp class directly in type-safe manner.
*
**************************************/
tm* const times = static_cast<struct tm*>(timesArg);
try
{
int intFractions;
TimeZoneUtil::decodeTimeStamp(*timeStampTz, times, &intFractions);
if (fractions)
*fractions = (ULONG) intFractions;
if (buffer)
TimeZoneUtil::format(buffer, bufferSize, timeStampTz->timestamp_zone);
}
catch (const Firebird::Exception&)
{
//// FIXME:
}
}
ISC_STATUS API_ROUTINE gds__encode(ISC_STATUS code, USHORT facility) ISC_STATUS API_ROUTINE gds__encode(ISC_STATUS code, USHORT facility)
{ {
/************************************** /**************************************