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:
parent
8792dff315
commit
141f62611b
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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, ×, &fractions);
|
||||||
|
|
||||||
SSHORT atDisplacement;
|
return TimeStamp::encode_timestamp(×, 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, ×, 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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
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;
|
||||||
|
@ -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
|
||||||
|
@ -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(×2);
|
||||||
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)
|
if (expect_type == expect_sql_time_tz || expect_type == expect_timestamp_tz || zone != sessionTimeZone)
|
||||||
|
TimeZoneUtil::localTimeStampToUtc(*date);
|
||||||
|
|
||||||
|
if (zone != sessionTimeZone)
|
||||||
{
|
{
|
||||||
ISC_TIME_TZ timeTz;
|
if (expect_type == expect_sql_time)
|
||||||
timeTz.time_time = date->timestamp_time;
|
{
|
||||||
timeTz.time_zone = zone;
|
ISC_TIME_TZ timeTz;
|
||||||
date->timestamp_time = TimeZoneUtil::timeTzAtZone(timeTz, cb->getSessionTimeZone());
|
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_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(×, 0, sizeof(struct tm));
|
memset(×, 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,
|
||||||
×.tm_hour, ×.tm_min, ×.tm_sec, &fractions);
|
×.tm_hour, ×.tm_min, ×.tm_sec, &fractions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case dtype_sql_time_tz:
|
||||||
|
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address, ×, &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, ×);
|
Firebird::TimeStamp::decode_date(*(GDS_DATE *) from->dsc_address, ×);
|
||||||
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, ×, &fractions);
|
Firebird::TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) from->dsc_address, ×, &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, ×, &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*/)
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
timeStampTz.timestamp_date = TimeStamp::getCurrentTimeStamp().value().timestamp_date; //// FIXME: ???
|
tempDsc.makeTimestampTz(&timeStampTz);
|
||||||
timeStampTz.timestamp_time = ((ISC_TIME_TZ*) value->dsc_address)->time_time;
|
MOV_move(tdbb, value, &tempDsc);
|
||||||
timeStampTz.timestamp_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
// else fall into
|
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, ×, &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:
|
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, ×, &fractions);
|
TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) value->dsc_address, ×, &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, ×, &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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -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:
|
||||||
isc_decode_timestamp(var->value.asDateTime, ×);
|
{
|
||||||
|
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||||
|
ULONG fractions;
|
||||||
|
|
||||||
|
if (dtype == SQL_TIMESTAMP_TZ)
|
||||||
|
isc_decode_timestamp_tz(var->value.asDateTimeTz, ×, &fractions, timeZone, sizeof(timeZone));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isc_decode_timestamp(var->value.asDateTime, ×);
|
||||||
|
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:
|
||||||
isc_decode_sql_time(var->value.asTime, ×);
|
{
|
||||||
|
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||||
|
ULONG fractions;
|
||||||
|
|
||||||
|
if (dtype == SQL_TIME_TZ)
|
||||||
|
isc_decode_sql_time_tz(var->value.asTimeTz, ×, &fractions, timeZone, sizeof(timeZone));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isc_decode_sql_time(var->value.asTime, ×);
|
||||||
|
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, ×);
|
isc_decode_sql_date(var->value.asDate, ×);
|
||||||
|
@ -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),
|
||||||
|
@ -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)
|
||||||
result->makeTimestamp();
|
{
|
||||||
|
if (args[1]->dsc_dtype == dtype_timestamp)
|
||||||
|
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(×, &fractions);
|
timestamp.decode(×, &fractions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case dtype_timestamp_tz:
|
||||||
|
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, ×, &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;
|
||||||
|
@ -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*) ×tampTz;
|
||||||
|
|
||||||
dsc descTimestamp;
|
dsc descTimestamp;
|
||||||
descTimestamp.makeTimestamp(×tamp);
|
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);
|
||||||
|
@ -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*) ×tamp1;
|
|
||||||
timestamp2 = TimeZoneUtil::timeStampTzAtZone(*(ISC_TIMESTAMP_TZ*) p2, TimeZoneUtil::UTC_ZONE);
|
|
||||||
p2 = (const UCHAR*) ×tamp2;
|
|
||||||
// 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;
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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 *);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user