8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 18:43: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

@ -7,16 +7,16 @@
# License Version 1.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy
# of the License at http://www.Inprise.com/IPL.html
#
#
# Software distributed under the License is distributed on an
# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
# or implied. See the License for the specific language governing
# rights and limitations under the License.
#
#
# The Original Code was created by Inprise Corporation
# and its predecessors. Portions created by Inprise Corporation are
# Copyright (C) Inprise Corporation.
#
#
# Created from fbclient.def by Nickolay Samofatov
#
# All Rights Reserved.
@ -170,7 +170,7 @@ isc_get_segment
isc_open_blob
isc_open_blob2
isc_put_segment
# Database functions
isc_attach_database
@ -352,6 +352,9 @@ fb_get_transaction_handle
fb_database_crypt_callback
fb_dsql_set_timeout
isc_decode_sql_time_tz
isc_decode_timestamp_tz
# Other misc functions
isc_ftof

View File

@ -167,7 +167,7 @@ EXPORTS
isc_open_blob @144
isc_open_blob2 @145
isc_put_segment @152
; Database functions
isc_attach_database @103
@ -357,8 +357,11 @@ EXPORTS
fb_get_transaction_handle
fb_database_crypt_callback
gds__trace
gds__trace_raw
isc_decode_sql_time_tz
isc_decode_timestamp_tz
gds__trace
gds__trace_raw
gds__trace_printer
gds__parse_bpb2

View File

@ -24,10 +24,14 @@
* Contributor(s): ______________________________________.
*/
//// TODO: Configure ICU time zone data files.
//// TODO: Update Windows ICU.
#include "firebird.h"
#include "../common/TimeZoneUtil.h"
#include "../common/StatusHolder.h"
#include "../common/unicode_util.h"
#include "../common/classes/timestamp.h"
#include "unicode/ucal.h"
using namespace Firebird;
@ -35,14 +39,13 @@ using namespace Firebird;
struct TimeZoneDesc
{
USHORT id;
const char* abbr;
const char* abbr; //// FIXME: remove
const UChar* icuName;
};
//-------------------------------------
static SSHORT getDisplacement(const ISC_TIMESTAMP_TZ& timeStampTz);
static SSHORT getDisplacement(const ISC_TIMESTAMP& timeStampUtc, USHORT timeZone);
static const TimeZoneDesc& getDesc(USHORT timeZone);
static inline bool isOffset(USHORT timeZone);
static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm);
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:
{0, "BRT"},
{1, "BRST"}
{"GMT", TZSTR_GMT},
{"America/Sao_Paulo", TZSTR_AMERICA_SAO_PAULO},
{"America/Los_Angeles", TZSTR_AMERICA_LOS_ANGELES}
};
//-------------------------------------
//// FIXME: Windows and others ports.
// Return the current user's time zone.
USHORT TimeZoneUtil::getCurrent()
struct TimeZoneStartup
{
//// FIXME: Return the time zone region instead of the offset.
time_t rawtime;
time(&rawtime);
TimeZoneStartup(MemoryPool& p)
: systemTimeZone(TimeZoneUtil::UTC_ZONE)
{
UErrorCode icuErrorCode = U_ZERO_ERROR;
struct tm tm1;
if (!localtime_r(&rawtime, &tm1))
system_call_failed::raise("localtime_r");
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(NULL, -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
int sign = tm1.tm_gmtoff < 0 ? -1 : 1;
unsigned tzh = (unsigned) abs(int(tm1.tm_gmtoff / 60 / 60));
unsigned tzm = (unsigned) abs(int(tm1.tm_gmtoff / 60 % 60));
if (!icuCalendar)
{
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.
@ -139,13 +204,7 @@ unsigned TimeZoneUtil::format(char* buffer, size_t bufferSize, USHORT timeZone)
}
else
{
if (MAX_USHORT - timeZone < FB_NELEM(TIME_ZONE_LIST))
strncpy(buffer, TIME_ZONE_LIST[MAX_USHORT - timeZone].abbr, bufferSize);
else
{
fb_assert(false);
strncpy(buffer, "*Invalid*", bufferSize);
}
strncpy(buffer, getDesc(timeZone).abbr, bufferSize);
p += strlen(buffer);
}
@ -169,13 +228,36 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
displacement = offsetZoneToDisplacement(timeStampTz.timestamp_zone);
else
{
ISC_TIMESTAMP ts1 = *(ISC_TIMESTAMP*) &timeStampTz;
ISC_TIMESTAMP ts2 = timeStampTzAtZone(timeStampTz, UTC_ZONE);
UErrorCode icuErrorCode = U_ZERO_ERROR;
displacement =
((ts1.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + ts1.timestamp_time) -
(ts2.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY + ts2.timestamp_time)) /
(ISC_TIME_SECONDS_PRECISION * 60);
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.");
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;
@ -185,95 +267,163 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
*tzm = displacement % 60;
}
// Moves a time from one time zone to another.
ISC_TIME TimeZoneUtil::timeTzAtZone(const ISC_TIME_TZ& timeTz, USHORT atTimeZone)
// Converts a time-tz to a time in a given zone.
ISC_TIME TimeZoneUtil::timeTzToTime(const ISC_TIME_TZ& timeTz, USHORT toTimeZone)
{
//// 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;
return timeStampTzAtZone(tempTimeStampTz, atTimeZone).timestamp_time;
return timeStampTzToTimeStamp(tempTimeStampTz, toTimeZone).timestamp_time;
}
// Moves a timestamp from one time zone to another.
ISC_TIMESTAMP TimeZoneUtil::timeStampTzAtZone(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT atTimeZone)
// Converts a timestamp-tz to a timestamp in a given zone.
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 -
(timeDisplacement * 60 * ISC_TIME_SECONDS_PRECISION);
struct tm times;
int fractions;
decodeTimeStamp(tempTimeStampTz, &times, &fractions);
SSHORT atDisplacement;
return TimeStamp::encode_timestamp(&times, fractions);
}
if (isOffset(atTimeZone))
atDisplacement = offsetZoneToDisplacement(atTimeZone);
// Converts a time from local to UTC.
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
{
ISC_TIMESTAMP tempTimeStampUtc;
tempTimeStampUtc.timestamp_date = ticks / TimeStamp::ISC_TICKS_PER_DAY;
tempTimeStampUtc.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
tm times;
TimeStamp::decode_timestamp(*(ISC_TIMESTAMP*) &timeStampTz, &times, nullptr);
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.");
}
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 -= -atDisplacement * 60 * ISC_TIME_SECONDS_PRECISION;
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;
ts.timestamp_date = 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 SSHORT getDisplacement(const ISC_TIMESTAMP_TZ& timeStampTz)
static const TimeZoneDesc& getDesc(USHORT timeZone)
{
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))
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;
}
}
}
// 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;
}
}
status_exception::raise(Arg::Gds(isc_random) << "Invalid time zone id"); //// TODO:
return *(TimeZoneDesc*) nullptr;
}
// 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;
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;
unsigned len = str - start;

View File

@ -36,10 +36,12 @@ class TimeZoneUtil
public:
static const unsigned ONE_DAY = 24 * 60; // used for offset encoding
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:
static USHORT getCurrent();
static USHORT getSystemTimeZone();
static USHORT parse(const char* str, unsigned strLen);
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 ISC_TIME timeTzAtZone(const ISC_TIME_TZ& timeTz, USHORT atTimeZone);
static ISC_TIMESTAMP timeStampTzAtZone(const ISC_TIMESTAMP_TZ& timeStampTz, USHORT atTimeZone);
static ISC_TIME timeTzToTime(const ISC_TIME_TZ& timeTz, USHORT toTimeZone);
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

View File

@ -653,10 +653,14 @@ void CVT_string_to_datetime(const dsc* desc,
*(ISC_TIMESTAMP*) date = Firebird::TimeStamp::getCurrentTimeStamp().value();
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 (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz)
TimeZoneUtil::localTimeStampToUtc(*date);
return;
}
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;
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz)
TimeZoneUtil::localTimeStampToUtc(*date);
if (strcmp(temp, TODAY) == 0)
return;
@ -767,7 +774,8 @@ void CVT_string_to_datetime(const dsc* desc,
return;
}
USHORT zone = cb->getSessionTimeZone();
USHORT sessionTimeZone = cb->getSessionTimeZone();
USHORT zone = sessionTimeZone;
if (expect_type != expect_sql_date)
{
@ -879,12 +887,13 @@ void CVT_string_to_datetime(const dsc* desc,
}
else
{
// The date portion isn't needed for time - but to
// keep the conversion in/out of isc_time clean lets
// initialize it properly anyway
times.tm_year = 0;
times.tm_mon = 0;
times.tm_mday = 1;
// Fetch current date
tm times2;
Firebird::TimeStamp::getCurrentTimeStamp().decode(&times2);
times.tm_year = times2.tm_year;
times.tm_mon = times2.tm_mon;
times.tm_mday = times2.tm_mday;
}
// 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_zone = zone;
if (expect_type == expect_sql_time)
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz || zone != sessionTimeZone)
TimeZoneUtil::localTimeStampToUtc(*date);
if (zone != sessionTimeZone)
{
ISC_TIME_TZ timeTz;
timeTz.time_time = date->timestamp_time;
timeTz.time_zone = zone;
date->timestamp_time = TimeZoneUtil::timeTzAtZone(timeTz, cb->getSessionTimeZone());
if (expect_type == expect_sql_time)
{
ISC_TIME_TZ timeTz;
timeTz.time_time = date->timestamp_time;
timeTz.time_zone = zone;
date->timestamp_time = TimeZoneUtil::timeTzToTime(timeTz, sessionTimeZone);
}
else if (expect_type == expect_timestamp)
*(ISC_TIMESTAMP*) date = TimeZoneUtil::timeStampTzToTimeStamp(*date, sessionTimeZone);
}
else if (expect_type == expect_timestamp)
*(ISC_TIMESTAMP*) date = TimeZoneUtil::timeStampTzAtZone(*date, cb->getSessionTimeZone());
}
@ -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_zone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
*(ISC_TIMESTAMP*) to->dsc_address =
TimeZoneUtil::timeStampTzAtZone(tsTz, cb->getSessionTimeZone());
TimeZoneUtil::timeStampTzToTimeStamp(tsTz, cb->getSessionTimeZone());
return;
}
case dtype_timestamp_tz:
*(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;
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_time = ((ISC_TIME_TZ*) from->dsc_address)->time_time;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*(ISC_TIMESTAMP_TZ*) to->dsc_address);
return;
case dtype_sql_time_tz:
// 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_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;
@ -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_time = 0;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*(ISC_TIMESTAMP_TZ*) to->dsc_address);
return;
case dtype_timestamp:
*(ISC_TIMESTAMP*) to->dsc_address = *(ISC_TIMESTAMP*) from->dsc_address;
((ISC_TIMESTAMP_TZ*) to->dsc_address)->timestamp_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeStampToUtc(*((ISC_TIMESTAMP_TZ*) to->dsc_address));
return;
default:
@ -1644,7 +1663,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
return;
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;
return;
@ -1683,7 +1702,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_sql_time_tz:
*(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;
case dtype_timestamp:
@ -1691,7 +1710,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
return;
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;
return;
@ -1731,11 +1750,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_sql_time:
*(ISC_TIME*) to->dsc_address = *(ISC_TIME*) from->dsc_address;
((ISC_TIME_TZ*) to->dsc_address)->time_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeToUtc(*(ISC_TIME_TZ*) to->dsc_address);
return;
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_zone = cb->getSessionTimeZone();
TimeZoneUtil::localTimeToUtc(*(ISC_TIME_TZ*) to->dsc_address);
return;
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));
int fractions = 0;
USHORT timezone;
switch (from->dsc_dtype)
{
case dtype_sql_time:
case dtype_sql_time_tz:
Firebird::TimeStamp::decode_time(*(GDS_TIME*) from->dsc_address,
&times.tm_hour, &times.tm_min, &times.tm_sec, &fractions);
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:
Firebird::TimeStamp::decode_date(*(GDS_DATE *) from->dsc_address, &times);
break;
case dtype_timestamp:
case dtype_timestamp_tz:
cb->isVersion4(version4); // Used in the conversion to text some lines below.
Firebird::TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) from->dsc_address, &times, &fractions);
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:
fb_assert(false);
cb->err(Arg::Gds(isc_badblk)); // internal error
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
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;
// 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_sql_date:
case dtype_sql_time:
case dtype_sql_time_tz:
case dtype_timestamp:
case dtype_timestamp_tz:
case dtype_array:
case dtype_dbkey:
case dtype_boolean:
@ -3408,7 +3429,7 @@ namespace
USHORT CommonCallbacks::getSessionTimeZone()
{
return TimeZoneUtil::UTC_ZONE;
return TimeZoneUtil::getSystemTimeZone();
}
void CommonCallbacks::isVersion4(bool& /*v4*/)

View File

@ -27,6 +27,7 @@
#include <string.h>
#include <stdlib.h>
#include "../common/dsc.h"
#include "../common/TimeZoneUtil.h"
#include "../jrd/ibase.h"
#include "../jrd/intl.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)
42, // dtype_dec128 +- . e +- coeff + exp
36, // dtype_dec_fixed coeff(34) + 1(+-) + 1(.)
20, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN
31 // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN
14 + TimeZoneUtil::MAX_LEN, // dtype_sql_time_tz 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>

View File

@ -277,6 +277,19 @@ private:
(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:
@ -302,6 +315,7 @@ public:
private:
AutoPtr<ModuleLoader::Module> module;
AutoPtr<ModuleLoader::Module> inModule;
};
static ImplementConversionICU* convIcu = NULL;

View File

@ -32,6 +32,7 @@
#include "../common/os/mod_loader.h"
#include "../common/classes/fb_string.h"
#include <unicode/ucnv.h>
#include <unicode/ucal.h>
struct UCollator;
struct USet;
@ -120,6 +121,18 @@ public:
int8_t (U_EXPORT2* ucnv_getMaxCharSize) (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;
};

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->vlux_count;
if (dialect1)
ArithmeticNode::add(desc, impure, this, blr_add);
ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
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
@ -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->vlux_count;
if (dialect1)
ArithmeticNode::add(desc, impure, this, blr_add);
ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
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

View File

@ -177,7 +177,7 @@ static const SCHAR DIALECT_1_TIMESTAMP_SCALE = 0;
static bool couldBeDate(const dsc desc);
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 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_subtract:
return add(desc2, impure, this, blrOp);
return add(tdbb, desc2, impure, this, blrOp);
case blr_divide:
{
@ -1848,7 +1848,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const
{
case blr_add:
case blr_subtract:
return add2(desc2, impure, this, blrOp);
return add2(tdbb, desc2, impure, this, blrOp);
case blr_multiply:
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.
// 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);
thread_db* tdbb = JRD_get_thread_data();
#ifdef DEV_BUILD
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)
{
fb_assert(arithmeticNode);
return arithmeticNode->addDateTime(desc, value);
return arithmeticNode->addDateTime(tdbb, desc, value);
}
// 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
// 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);
@ -1980,11 +1981,9 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN
if (node->nodFlags & FLAG_DATE)
{
fb_assert(arithmeticNode);
return arithmeticNode->addDateTime(desc, value);
return arithmeticNode->addDateTime(tdbb, desc, value);
}
thread_db* tdbb = JRD_get_thread_data();
// Handle decimal arithmetic
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.
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?
@ -2526,7 +2525,7 @@ dsc* ArithmeticNode::addDateTime(const dsc* desc, impure_value* value) const
{
case dtype_sql_time:
case dtype_sql_time_tz:
return addSqlTime(desc, value);
return addSqlTime(tdbb, desc, value);
case dtype_sql_date:
return addSqlDate(desc, value);
@ -2540,7 +2539,7 @@ dsc* ArithmeticNode::addDateTime(const dsc* desc, impure_value* value) const
default:
// This needs to handle a dtype_sql_date + dtype_sql_time
// For historical reasons prior to V6 - handle any types for timestamp arithmetic
return addTimeStamp(desc, value);
return addTimeStamp(tdbb, desc, value);
}
return NULL;
@ -2620,78 +2619,67 @@ dsc* ArithmeticNode::addSqlDate(const dsc* desc, impure_value* value) const
// TIME - TIME Result is SLONG, scale -4
// TIME +/- NUMERIC 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);
dsc* result = &value->vlu_desc;
thread_db* tdbb = JRD_get_thread_data();
Attachment* const attachment = tdbb->getAttachment();
fb_assert(value->vlu_desc.isTime() || desc->isTime());
bool op1_is_time = value->vlu_desc.isTime();
bool op2_is_time = desc->isTime();
bool op1_is_tz = value->vlu_desc.isDateTimeTz();
bool op2_is_tz = desc->isDateTimeTz();
const dsc* op1_desc = &value->vlu_desc;
const dsc* op2_desc = desc;
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
USHORT tz1 = TimeZoneUtil::UTC_ZONE;
SINT64 d1;
if (op1_is_time)
{
if (op1_is_tz)
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;
d1 = *(GDS_TIME*) op1_desc->dsc_address;
fb_assert(d1 >= 0 && d1 < ISC_TICKS_PER_DAY);
}
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
USHORT tz2 = TimeZoneUtil::UTC_ZONE;
SINT64 d2;
if (op2_is_time)
{
if (op2_is_tz)
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;
d2 = *(GDS_TIME*) op2_desc->dsc_address;
fb_assert(d2 >= 0 && d2 < ISC_TICKS_PER_DAY);
}
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)
{
@ -2732,18 +2720,18 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const
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_scale = 0;
result->dsc_sub_type = 0;
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)
((ISC_TIME_TZ*) result->dsc_address)->time_zone = tz1;
else if (op2_is_tz)
((ISC_TIME_TZ*) result->dsc_address)->time_zone = tz2;
if (op1_tz.specified)
value->vlu_misc.vlu_sql_time_tz.time_zone = op1_tz.value;
else if (op2_tz.specified)
value->vlu_misc.vlu_sql_time_tz.time_zone = op2_tz.value;
return result;
}
@ -2754,26 +2742,51 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const
// NUMERIC +/- TIMESTAMP Numeric is interpreted as days DECIMAL(*,*).
// DATE + TIME
// 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);
bool op1_is_tz = value->vlu_desc.isDateTimeTz();
bool op2_is_tz = desc->isDateTimeTz();
USHORT tz1 = TimeZoneUtil::UTC_ZONE;
USHORT tz2 = TimeZoneUtil::UTC_ZONE;
const dsc* op1_desc = &value->vlu_desc;
const dsc* op2_desc = desc;
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() ?
((ISC_TIME_TZ*) value->vlu_desc.dsc_address)->time_zone :
((ISC_TIMESTAMP_TZ*) value->vlu_desc.dsc_address)->timestamp_zone;
if (op1_desc->dsc_dtype == dtype_sql_time)
op1_tz_desc.makeTimeTz(&op1_time_tz);
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() ?
((ISC_TIME_TZ*) desc->dsc_address)->time_zone :
((ISC_TIMESTAMP_TZ*) desc->dsc_address)->timestamp_zone;
if (op2_desc->dsc_dtype == dtype_sql_time)
op2_tz_desc.makeTimeTz(&op2_time_tz);
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;
@ -2782,24 +2795,24 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
// 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
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_time = *(GDS_TIME*) desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_date = *(GDS_DATE*) op1_desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_time = *(GDS_TIME*) op2_desc->dsc_address;
}
else
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
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_date = *(GDS_DATE*) desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_time = *(GDS_TIME*) op1_desc->dsc_address;
value->vlu_misc.vlu_timestamp_tz.timestamp_date = *(GDS_DATE*) op2_desc->dsc_address;
}
else
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 */
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
<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 (!(value->vlu_desc.isTimeStamp() ||
DTYPE_IS_TEXT(value->vlu_desc.dsc_dtype)))
{
if (!(op1_desc->isTimeStamp() || DTYPE_IS_TEXT(op1_desc->dsc_dtype)))
ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_onlycansub_tstampfromtstamp));
}
d1 = getTimeStampToIscTicks(&value->vlu_desc, true);
d2 = getTimeStampToIscTicks(desc, true);
d1 = getTimeStampToIscTicks(tdbb, op1_desc);
d2 = getTimeStampToIscTicks(tdbb, op2_desc);
d2 = d1 - d2;
@ -2898,10 +2908,10 @@ dsc* ArithmeticNode::addTimeStamp(const dsc* desc, impure_value* value) const
a timestamp */
// 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
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
// 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)
{
d1 = getTimeStampToIscTicks(&value->vlu_desc, false);
d2 = getDayFraction(desc);
d1 = getTimeStampToIscTicks(tdbb, op1_desc);
d2 = getDayFraction(op2_desc);
}
else
{
fb_assert(blrOp == blr_add);
fb_assert(op2_is_timestamp);
d1 = getDayFraction(&value->vlu_desc);
d2 = getTimeStampToIscTicks(desc, false);
d1 = getDayFraction(op1_desc);
d2 = getTimeStampToIscTicks(tdbb, op2_desc);
}
// 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 &&
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_scale = 0;
result->dsc_sub_type = 0;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_timestamp_tz;
if (op1_is_tz)
((ISC_TIMESTAMP_TZ*) result->dsc_address)->timestamp_zone = tz1;
else if (op2_is_tz)
((ISC_TIMESTAMP_TZ*) result->dsc_address)->timestamp_zone = tz2;
if (op1_tz.specified)
value->vlu_misc.vlu_timestamp_tz.timestamp_zone = op1_tz.value;
else if (op2_tz.specified)
value->vlu_misc.vlu_timestamp_tz.timestamp_zone = op2_tz.value;
return result;
}
@ -3183,31 +3193,15 @@ dsc* AtNode::execute(thread_db* tdbb, jrd_req* request) const
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);
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())
{
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);
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
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;
}
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);
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());
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;
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_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_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;
}
@ -4226,7 +4227,7 @@ ValueExprNode* CurrentTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/)
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);
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_length = type_lengths[dtype_sql_time_tz];
((ISC_TIME_TZ*) impure->vlu_desc.dsc_address)->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_time = encTimes.timestamp_time;
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;
}
@ -4341,7 +4344,7 @@ ValueExprNode* CurrentTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch
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);
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_length = type_lengths[dtype_timestamp_tz];
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_date = encTimes.timestamp_date;
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_time = encTimes.timestamp_time;
((ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address)->timestamp_zone = TimeZoneUtil::getCurrent();
impure->vlu_misc.vlu_timestamp_tz.timestamp_date = encTimes.timestamp_date;
impure->vlu_misc.vlu_timestamp_tz.timestamp_time = encTimes.timestamp_time;
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;
}
@ -5254,7 +5259,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_week:
if (!nodeIs<NullNode>(sub1) &&
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) <<
Arg::Gds(isc_extract_input_mismatch));
@ -5266,8 +5271,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_second:
case blr_extract_millisecond:
if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_time &&
sub1->nodDesc.dsc_dtype != dtype_timestamp)
!sub1->nodDesc.isTime() &&
!sub1->nodDesc.isTimeStamp())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
@ -5277,8 +5282,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_time_tz &&
sub1->nodDesc.dsc_dtype != dtype_timestamp_tz)
!sub1->nodDesc.isTime() &&
!sub1->nodDesc.isTimeStamp())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
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);
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))
return NULL;
@ -5414,7 +5419,6 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
switch (value->dsc_dtype)
{
case dtype_sql_time:
case dtype_sql_time_tz:
switch (blrSubOp)
{
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_minute:
if (value->dsc_dtype == dtype_sql_time_tz)
{
timeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date; //// FIXME: ???
timeStampTz.timestamp_time = ((ISC_TIME_TZ*) value->dsc_address)->time_time;
timeStampTz.timestamp_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone;
break;
}
// else fall into
{
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_time = ((ISC_TIME_TZ*) value->dsc_address)->time_time;
timeStampTz.timestamp_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone;
break;
default:
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_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;
}
default:
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:
timeStampTz = *(ISC_TIMESTAMP_TZ*) value->dsc_address;
break;
default:
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, &times, &fractions);
}
break;
@ -7898,7 +7929,7 @@ ValueExprNode* LocalTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/)
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);
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());
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);
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_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;
}
@ -7997,7 +8033,7 @@ ValueExprNode* LocalTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/
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);
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());
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);
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_length = type_lengths[dtype_timestamp];
*((ISC_TIMESTAMP*) impure->vlu_desc.dsc_address) = encTimes;
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
// set the correct scale; if it is approximate numeric,
// the first add() will convert impure to double.
ArithmeticNode::add(desc, impure, this, blr_add);
ArithmeticNode::add(tdbb, desc, impure, this, blr_add);
++count;
}
@ -13395,32 +13438,22 @@ static SINT64 getDayFraction(const dsc* d)
// date and time in MJD time arithmetic.
// 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.
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;
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_flags = 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);
CVT_move(d, &result, tdbb->getAttachment()->att_dec_status);
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 +
(SINT64) result_timestamp.timestamp_time - delta;
}

View File

@ -93,17 +93,19 @@ public:
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
// 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* add2(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,
const UCHAR blrOp);
static dsc* add2(thread_db* tdbb, const dsc* desc, impure_value* value, const ValueExprNode* node,
const UCHAR blrOp);
private:
dsc* multiply(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* 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* addSqlTime(const dsc* desc, impure_value* value) const;
dsc* addTimeStamp(const dsc* desc, impure_value* value) const;
dsc* addSqlTime(thread_db* tdbb, const dsc* desc, impure_value* value) const;
dsc* addTimeStamp(thread_db* tdbb, const dsc* desc, impure_value* value) const;
private:
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
EXPECT_DATETIME expect;
EXPECT_DATETIME expect1, expect2;
switch (numeric_flag)
{
case CONSTANT_DATE:
expect = expect_sql_date;
expect1 = expect2 = expect_sql_date;
break;
case CONSTANT_TIME:
expect = expect_sql_time_tz;
expect1 = expect_sql_time_tz;
expect2 = expect_sql_time;
break;
case CONSTANT_TIMESTAMP:
expect = expect_timestamp_tz;
expect1 = expect_timestamp_tz;
expect2 = expect_timestamp;
break;
default:
@ -180,7 +182,10 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag)
ISC_TIMESTAMP_TZ ts;
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)
{

View File

@ -1071,6 +1071,7 @@ interface Util : Versioned
void decodeTime(ISC_TIME time, uint* hours, uint* minutes, uint* seconds, uint* fractions);
ISC_DATE encodeDate(uint year, uint month, uint day);
ISC_TIME encodeTime(uint hours, uint minutes, uint seconds, uint fractions);
//// TODO: TZ functions
uint formatStatus(string buffer, uint bufferSize, Status status);
uint getClientVersion(); // Returns major * 256 + minor
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 DATE_LEN = 11; // 11 for date only
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_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 BOOLEAN_LEN = 7; // <false>
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";
TEXT d[32];
TEXT d[64];
TEXT* p = *s;
*p = '\0';
@ -7403,7 +7403,17 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
case SQL_TIMESTAMP:
case SQL_TIMESTAMP_TZ:
isc_decode_timestamp(var->value.asDateTime, &times);
{
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);
fractions = ((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION;
}
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_mday, times.tm_hour, times.tm_min,
times.tm_sec,
((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION);
fractions);
}
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_year + 1900, times.tm_hour, times.tm_min,
times.tm_sec,
((ULONG*) var->value.asChar)[1] % ISC_TIME_SECONDS_PRECISION);
fractions);
else
sprintf(d, "%2d-%s-%4d", times.tm_mday,
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);
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);
@ -7439,19 +7449,31 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
isqlGlob.printf("%s%s", d, NEWLINE);
break;
}
case SQL_TYPE_TIME:
case SQL_TIME_TZ:
isc_decode_sql_time(var->value.asTime, &times);
{
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);
fractions = (*var->value.asTime) % ISC_TIME_SECONDS_PRECISION;
}
sprintf(d, "%2.2d:%2.2d:%2.2d.%4.4" ULONGFORMAT,
times.tm_hour, times.tm_min, times.tm_sec,
(*var->value.asTime) % ISC_TIME_SECONDS_PRECISION);
fractions);
if (dtype == SQL_TIME_TZ)
{
size_t len = strlen(d);
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);
@ -7460,6 +7482,7 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
isqlGlob.printf("%s%s", d, NEWLINE);
break;
}
case SQL_TYPE_DATE:
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_call_depth(0),
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_utility(UTIL_NONE),
att_procedures(*pool),

View File

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

View File

@ -2602,8 +2602,7 @@ static void compress(thread_db* tdbb,
}
else if (itype == idx_sql_time_tz)
{
ISC_TIME_TZ timeTz = MOV_get_sql_time_tz(desc);
temp.temp_ulong = TimeZoneUtil::timeTzAtZone(timeTz, TimeZoneUtil::UTC_ZONE);
temp.temp_ulong = MOV_get_sql_time_tz(desc).time_time;
temp_copy_length = sizeof(ULONG);
temp_is_negative = false;
@ -2627,10 +2626,10 @@ static void compress(thread_db* tdbb,
else if (desc->dsc_dtype == dtype_timestamp_tz)
{
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;
descTimestamp.makeTimestamp(&timestamp);
descTimestamp.makeTimestamp(timestamp);
temp.temp_double = MOV_date_to_double(&descTimestamp);
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
ISC_TIME time1, time2;
ISC_TIMESTAMP timestamp1, timestamp2;
if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale)
{
const UCHAR* p1 = arg1->dsc_address;
@ -239,12 +236,6 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
return -1;
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:
if (*(ULONG *) p1 == *(ULONG *) p2)
return 0;
@ -283,12 +274,6 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
}
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:
if (((SLONG *) p1)[0] > ((SLONG *) p2)[0])
return 1;

View File

@ -100,71 +100,6 @@ namespace
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;
// 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);
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);
#endif
UtcConversor utcConversor(rpb);
const Compressor dcc(*tdbb->getDefaultPool(), rpb->rpb_length, rpb->rpb_address);
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));
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 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*);
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*);
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_db_handle *);

View File

@ -675,7 +675,7 @@ namespace Jrd
struct DummyAdjustFunctor
{
void operator ()(impure_value* target)
void operator ()(thread_db* /*tdbb*/, impure_value* /*target*/)
{
}
};
@ -736,7 +736,7 @@ namespace Jrd
else
{
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;

View File

@ -933,26 +933,10 @@ void Sort::diddleKey(UCHAR* record, bool direction)
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_tz:
case SKD_sql_time:
case SKD_sql_time_tz:
case SKD_sql_date:
p[3] ^= 1 << 7;
break;

View File

@ -47,6 +47,7 @@
#include "../yvalve/gds_proto.h"
#include "../common/os/path_utils.h"
#include "../common/dsc.h"
#include "../common/TimeZoneUtil.h"
#include "../jrd/constants.h"
#include "../jrd/status.h"
#include "../common/os/os_utils.h"
@ -133,6 +134,7 @@ const SLONG GENERIC_SQLCODE = -999;
#include "../common/classes/MsgPrint.h"
using Firebird::TimeStamp;
using Firebird::TimeZoneUtil;
using Firebird::BlrReader;
// 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)
{
/**************************************
@ -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)
{
/**************************************