mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:03:02 +01:00
None gmt fallback (#260)
Added new form of set bind: SET BIND OF TIME ZONE TO EXTENDED
This commit is contained in:
parent
684e17d0e4
commit
2d2df601a3
@ -11,8 +11,7 @@
|
||||
### Syntax is:
|
||||
|
||||
```sql
|
||||
SET BIND OF type-from TO { type-to | LEGACY };
|
||||
SET BIND OF type NATIVE;
|
||||
SET BIND OF { type-from | TIME ZONE } TO { type-to | LEGACY | EXTENDED | NATIVE };
|
||||
```
|
||||
|
||||
### Description:
|
||||
@ -21,9 +20,11 @@ Makes it possible to define rules of describing types of returned to the client
|
||||
`type-from` is replaced with `type-to`, automatic data coercion takes place.
|
||||
|
||||
When incomplete type definition is used (i.e. `CHAR` instead `CHAR(n)`) in left part of `SET BIND` coercion
|
||||
will take place for all `CHAR` columns, not only default `CHAR(1)`.
|
||||
will take place for all `CHAR` columns, not only default `CHAR(1)`. Special incomplete type `TIME ZONE`
|
||||
stands for all types (namely TIME & TIMESTAMP) WITH TIME ZONE.
|
||||
When incomplete type definiton is used in right side of the statement (TO part) firebird engine will define missing
|
||||
details about that type automatically based on source column.
|
||||
|
||||
From this statement POV there is no difference between NUMERIC and DECIMAL datatypes. Changing bind of any NUMERIC
|
||||
does not affect appropriate underlying integer type. On contrary, changing bind of integer datatype also affects
|
||||
appropriate NUMERICs.
|
||||
@ -40,6 +41,10 @@ legacy datatypes:
|
||||
| TIME WITH TIME ZONE | TIME WITHOUT TIME ZONE |
|
||||
| TIMESTAMP WITH TIME ZONE | TIMESTAMP WITHOUT TIME ZONE |
|
||||
|
||||
Using `EXTENDED` in the `TO` part directs firebird engine to use extended form of `FROM` datatype.
|
||||
Currently it works only for TIME/TIMESTAMP WITH TIME ZONE - they are coerced to EXTENDED TIME/TIMESTAMP WITH TIME ZONE
|
||||
appropriately.
|
||||
|
||||
Setting `NATIVE` means `type` will be used as if there were no previous rules for it.
|
||||
|
||||
Except SQL-statement there are two more ways to specify data coercion - tag `isc_dpb_set_bind` in DPB
|
||||
@ -100,3 +105,22 @@ CAST
|
||||
==========================================
|
||||
123.45
|
||||
```
|
||||
|
||||
In a case of missing ICU on client:
|
||||
```sql
|
||||
SELECT CURRENT_TIMESTAMP FROM RDB$DATABASE;
|
||||
```
|
||||
```
|
||||
CURRENT_TIMESTAMP
|
||||
=========================================================
|
||||
2020-02-21 16:26:48.0230 GMT*
|
||||
```
|
||||
```sql
|
||||
SET BIND OF TIME ZONE TO EXTENDED;
|
||||
SELECT CURRENT_TIMESTAMP FROM RDB$DATABASE;
|
||||
```
|
||||
```
|
||||
CURRENT_TIMESTAMP
|
||||
=========================================================
|
||||
2020-02-21 19:26:55.6820 +03:00
|
||||
```
|
||||
|
@ -1,20 +1,41 @@
|
||||
# Time Zone support (FB 4.0)
|
||||
|
||||
Time zone support consists of `TIME WITH TIME ZONE` and `TIMESTAMP WITH TIME ZONE` data types, expressions and statements to work with time zones and conversion between data types without/with time zones.
|
||||
Time zone support consists of `TIME WITH TIME ZONE` and `TIMESTAMP WITH TIME ZONE` data types,
|
||||
expressions and statements to work with time zones and conversion between data types without/with time zones.
|
||||
|
||||
The first important thing to understand is that `TIME WITHOUT TIME ZONE`, `TIMESTAMP WITHOUT TIME ZONE` and `DATE` data types are defined to use the session time zone when converting from or to a `TIME WITH TIME ZONE` or `TIMESTAMP WITH TIME ZONE`. `TIME` and `TIMESTAMP` are synonymous to theirs respectively `WITHOUT TIME ZONE` data types.
|
||||
The first important thing to understand is that `TIME WITHOUT TIME ZONE`, `TIMESTAMP WITHOUT TIME ZONE` and `DATE`
|
||||
data types are defined to use the session time zone when converting from or to a `TIME WITH TIME ZONE` or `TIMESTAMP WITH TIME ZONE`.
|
||||
`TIME` and `TIMESTAMP` are synonymous to theirs respectively `WITHOUT TIME ZONE` data types.
|
||||
|
||||
The session time zone, as the name implies, can be a different one for each database attachment. It can be set with the isc_dpb_session_time_zone DPB, and if not, it starts by default defined to be the `firebird.conf` parameter `DefaultTimeZone` or the same time zone used by the Firebird OS process when the parameter is not defined. A change in `DefaultTimeZone` configuration or the OS time zone does not changes the default of a running Firebird process.
|
||||
The session time zone, as the name implies, can be a different one for each database attachment.
|
||||
It can be set with the isc_dpb_session_time_zone DPB, and if not, it starts by default defined to be the
|
||||
`firebird.conf` parameter `DefaultTimeZone` or the same time zone used by the Firebird OS process when the parameter is not defined.
|
||||
A change in `DefaultTimeZone` configuration or the OS time zone does not changes the default of a running Firebird process.
|
||||
|
||||
It can then be changed with `SET TIME ZONE` statement to a given time zone or reset to its original value with `SET TIME ZONE LOCAL`.
|
||||
|
||||
The original time zone value is initially defined equal to the current time zone in session initialization and cannot be changed manually. But the original time zone is internally changed when a routine (function, procedure or trigger) is called to the value of the current time zone and restored to its previous value at routine exit. That means that a routine that changes the current time zone and later run `SET TIME ZONE LOCAL` will restore the current time zone to its initially received value.
|
||||
The original time zone value is initially defined equal to the current time zone in session initialization and cannot
|
||||
be changed manually. But the original time zone is internally changed when a routine (function, procedure or trigger)
|
||||
is called to the value of the current time zone and restored to its previous value at routine exit. That means that
|
||||
a routine that changes the current time zone and later run `SET TIME ZONE LOCAL` will restore the current time zone
|
||||
to its initially received value.
|
||||
|
||||
A time zone may be a string with a time zone region (for example, `America/Sao_Paulo`) or a hours:minutes displacement (for example, `-03:00`) from GMT.
|
||||
A time zone may be a string with a time zone region (for example, `America/Sao_Paulo`) or a hours:minutes displacement
|
||||
(for example, `-03:00`) from GMT.
|
||||
|
||||
A time/timestamp with time zone is considered equal to another time/timestamp with time zone if their conversion to UTC are equal, for example, `time '10:00 -02' = time '09:00 -03'`, since both are the same as `time '12:00 GMT'`. This is also valid in the context of `UNIQUE` constraints and for sorting purposes.
|
||||
A time/timestamp with time zone is considered equal to another time/timestamp with time zone if their conversion to UTC
|
||||
are equal, for example, `time '10:00 -02' = time '09:00 -03'`, since both are the same as `time '12:00 GMT'`.
|
||||
This is also valid in the context of `UNIQUE` constraints and for sorting purposes.
|
||||
|
||||
Some timestamps does not exist (DST starting) or repeats twice (DST ending). For the first case, when DST starts in America/New_York, 2:30 AM on March 12, 2017 does not exist and is interpreted as 2:30 AM UTC-05 (equivalent to 3:30 AM UTC-04). For the second case, when DST ends in America/New_York, 1:30 AM on November 5, 2017 repeats twice and is interpreted as 1:30 AM UTC-04 instead of 1:30 AM UTC-05.
|
||||
Some timestamps does not exist (DST starting) or repeats twice (DST ending). For the first case, when DST starts
|
||||
in America/New_York, 2:30 AM on March 12, 2017 does not exist and is interpreted as 2:30 AM UTC-05 (equivalent to
|
||||
3:30 AM UTC-04). For the second case, when DST ends in America/New_York, 1:30 AM on November 5, 2017 repeats twice and
|
||||
is interpreted as 1:30 AM UTC-04 instead of 1:30 AM UTC-05.
|
||||
|
||||
`EXTENDED TIME/TIMESTAMP WITH TIME ZONE` are intended for use only when communicating with a cliens,
|
||||
they solve a problem of representing correct time on clients missing ICU library. One can't use extended
|
||||
datatypes in tables, procedures, etc. The only way to use that datatypes is datatype coercion including
|
||||
SET BIND statement (see [README.set_bind](./README.set_bind.md) for further details).
|
||||
|
||||
|
||||
## Data types
|
||||
@ -23,18 +44,25 @@ Some timestamps does not exist (DST starting) or repeats twice (DST ending). For
|
||||
TIME [ { WITH | WITHOUT } TIME ZONE ]
|
||||
|
||||
TIMESTAMP [ { WITH | WITHOUT } TIME ZONE ]
|
||||
|
||||
EXTENDED { TIME | TIMESTAMP } WITH TIME ZONE
|
||||
```
|
||||
|
||||
### Storage
|
||||
|
||||
TIME/TIMESTAMP WITH TIME ZONE has respectively the same storage of TIME/TIMESTAMP WITHOUT TIME ZONE plus 2 bytes for the time zone identifier or displacement.
|
||||
TIME/TIMESTAMP WITH TIME ZONE has respectively the same storage of TIME/TIMESTAMP WITHOUT TIME ZONE
|
||||
plus 2 bytes for the time zone identifier or displacement.
|
||||
|
||||
The time/timestamp parts are stored in UTC (translated from the informed time zone).
|
||||
|
||||
Time zone identifiers (from regions) are put directly in the time_zone field. They start from 65535 (which is the GMT code) and are decreasing as new time zones were/are added.
|
||||
Time zone identifiers (from regions) are put directly in the time_zone field.
|
||||
They start from 65535 (which is the GMT code) and are decreasing as new time zones were/are added.
|
||||
|
||||
Time zone displacements (+/- HH:MM) are encoded with `(sign * (HH * 60 + MM)) + 1439`. For example, a `00:00` displacement is encoded as `(1 * (0 * 60 + 0)) + 1439 = 1439` and `-02:00` as `(-1 * (2 * 60 + 0)) + 1439 = 1319`.
|
||||
Time zone displacements (+/- HH:MM) are encoded with `(sign * (HH * 60 + MM)) + 1439`.
|
||||
For example, a `00:00` displacement is encoded as `(1 * (0 * 60 + 0)) + 1439 = 1439` and `-02:00` as `(-1 * (2 * 60 + 0)) + 1439 = 1319`.
|
||||
|
||||
EXTENDED TIME/TIMESTAMP WITH TIME ZONE have additionally more 2 bytes always containing absolute
|
||||
time zone offset in minutes.
|
||||
### API structs
|
||||
|
||||
```
|
||||
@ -49,6 +77,20 @@ struct ISC_TIMESTAMP_TZ
|
||||
ISC_TIMESTAMP utc_timestamp;
|
||||
ISC_USHORT time_zone;
|
||||
};
|
||||
|
||||
struct ISC_TIME_TZ_EX
|
||||
{
|
||||
ISC_TIME utc_time;
|
||||
ISC_USHORT time_zone;
|
||||
ISC_SHORT ext_offset;
|
||||
};
|
||||
|
||||
struct ISC_TIMESTAMP_TZ_EX
|
||||
{
|
||||
ISC_TIMESTAMP utc_timestamp;
|
||||
ISC_USHORT time_zone;
|
||||
ISC_SHORT ext_offset;
|
||||
};
|
||||
```
|
||||
|
||||
### API functions (FirebirdInterface.idl - IUtil interface)
|
||||
@ -101,9 +143,41 @@ void encodeTimeStampTz(
|
||||
uint fractions,
|
||||
const string timeZone
|
||||
);
|
||||
|
||||
void decodeTimeTzEx(
|
||||
Status status,
|
||||
const ISC_TIME_TZ_EX* timeTzEx,
|
||||
uint* hours,
|
||||
uint* minutes,
|
||||
uint* seconds,
|
||||
uint* fractions,
|
||||
uint timeZoneBufferLength,
|
||||
string timeZoneBuffer
|
||||
);
|
||||
|
||||
void decodeTimeStampTzEx(
|
||||
Status status,
|
||||
const ISC_TIMESTAMP_TZ_EX* timeStampTzEx,
|
||||
uint* year,
|
||||
uint* month,
|
||||
uint* day,
|
||||
uint* hours,
|
||||
uint* minutes,
|
||||
uint* seconds,
|
||||
uint* fractions,
|
||||
uint timeZoneBufferLength,
|
||||
string timeZoneBuffer
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
When `decodeTimeTz` / `decodeTimeStampTz` is called with non-null `timeZoneBuffer` and ICU could not be loaded in the client, `timeZoneBuffer` returns the string `GMT*` and the others fields receives the timestamp GMT values.
|
||||
When `decodeTimeTz` / `decodeTimeStampTz` is called with non-null `timeZoneBuffer` and ICU
|
||||
could not be loaded in the client, `timeZoneBuffer` returns the string `GMT*` and the others fields
|
||||
receives the timestamp GMT values.
|
||||
|
||||
When `decodeTimeTzEx` / `decodeTimeStampTzEx` is called with non-null `timeZoneBuffer` and ICU
|
||||
could not be loaded in the client, `timeZoneBuffer` returns the string `+/-HH:MM` and the other
|
||||
fields are set using specified `ext_offset`.
|
||||
|
||||
## Time zone string syntax
|
||||
|
||||
|
136
examples/udr/Zones.cpp
Normal file
136
examples/udr/Zones.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
* Alex Peshkoff
|
||||
*/
|
||||
|
||||
#include "UdrCppExample.h"
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/***
|
||||
create procedure gen_dates (
|
||||
start_date timestamp with time zone not null,
|
||||
n_days integer not null
|
||||
) returns (
|
||||
out_date timestamp with time zone not null
|
||||
)
|
||||
external name 'udrcpp_example!gen_dates'
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_PROCEDURE(gen_dates)
|
||||
// Without InMessage/OutMessage definitions, messages will be byte-based.
|
||||
|
||||
// Procedure variables.
|
||||
unsigned inOffsetStartDate, inOffsetNDays, outNullOffset, outOffset;
|
||||
|
||||
// Get offsets once per procedure.
|
||||
FB_UDR_CONSTRUCTOR
|
||||
{
|
||||
AutoRelease<IMessageMetadata> inMetadata(metadata->getInputMetadata(status));
|
||||
inOffsetStartDate = inMetadata->getOffset(status, 0);
|
||||
inOffsetNDays = inMetadata->getOffset(status, 1);
|
||||
// printf("SQLtype in = %d\n", inMetadata->getType(status, 0));
|
||||
|
||||
AutoRelease<IMessageMetadata> outMetadata(metadata->getOutputMetadata(status));
|
||||
outNullOffset = outMetadata->getNullOffset(status, 0);
|
||||
outOffset = outMetadata->getOffset(status, 0);
|
||||
// printf("SQLtype out = %d\n", outMetadata->getType(status, 0));
|
||||
}
|
||||
|
||||
/*** Procedure destructor.
|
||||
FB_UDR_DESTRUCTOR
|
||||
{
|
||||
}
|
||||
***/
|
||||
|
||||
FB_UDR_EXECUTE_PROCEDURE
|
||||
{
|
||||
counter = *(ISC_LONG*) (in + procedure->inOffsetNDays);
|
||||
run = *(ISC_TIMESTAMP_TZ*) (in + procedure->inOffsetStartDate);
|
||||
|
||||
*(ISC_SHORT*) (out + procedure->outNullOffset) = FB_FALSE;
|
||||
}
|
||||
|
||||
// After procedure's execute definition, starts the result set definition.
|
||||
|
||||
FB_UDR_FETCH_PROCEDURE
|
||||
{
|
||||
if (--counter < 0)
|
||||
return false;
|
||||
|
||||
*(ISC_TIMESTAMP_TZ*) (out + procedure->outOffset) = run;
|
||||
run.utc_timestamp.timestamp_date++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** ResultSet destructor.
|
||||
~ResultSet()
|
||||
{
|
||||
}
|
||||
***/
|
||||
|
||||
// ResultSet variables.
|
||||
ISC_LONG counter;
|
||||
ISC_TIMESTAMP_TZ run;
|
||||
FB_UDR_END_PROCEDURE
|
||||
|
||||
|
||||
/***
|
||||
create procedure gen_dates2 (
|
||||
start_date timestamp with time zone not null,
|
||||
n_days integer not null
|
||||
) returns (
|
||||
out_date timestamp with time zone not null
|
||||
)
|
||||
external name 'udrcpp_example!gen_dates2'
|
||||
engine udr;
|
||||
***/
|
||||
FB_UDR_BEGIN_PROCEDURE(gen_dates2)
|
||||
FB_UDR_MESSAGE(InMessage,
|
||||
(FB_TIMESTAMP_TZ, start_date)
|
||||
(FB_INTEGER, n_days)
|
||||
);
|
||||
|
||||
FB_UDR_MESSAGE(OutMessage,
|
||||
(FB_TIMESTAMP_TZ, o_date)
|
||||
);
|
||||
|
||||
FB_UDR_EXECUTE_PROCEDURE
|
||||
{
|
||||
out->o_dateNull = FB_FALSE;
|
||||
out->o_date = in->start_date;
|
||||
out->o_date.utcTimestamp.date--;
|
||||
counter = in->n_days;
|
||||
}
|
||||
|
||||
FB_UDR_FETCH_PROCEDURE
|
||||
{
|
||||
out->o_date.utcTimestamp.date++;
|
||||
return counter-- > 0;
|
||||
}
|
||||
|
||||
ISC_LONG counter;
|
||||
FB_UDR_END_PROCEDURE
|
||||
|
@ -154,6 +154,15 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool d
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
if (!xdr_long(xdrs, (SLONG*) p))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, (SSHORT*) (p + sizeof(SLONG))))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, (SSHORT*) (p + sizeof(SLONG) + sizeof(SSHORT))))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
if (!xdr_float(xdrs, (float*) p))
|
||||
return FALSE;
|
||||
@ -195,6 +204,17 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool d
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
if (!xdr_long(xdrs, (SLONG*) p))
|
||||
return FALSE;
|
||||
if (!xdr_long(xdrs, &((SLONG*) p)[1]))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, (SSHORT*) (p + sizeof(SLONG) + sizeof(SLONG))))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, (SSHORT*) (p + sizeof(SLONG) + sizeof(SLONG) + sizeof(SSHORT))))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_quad:
|
||||
case dtype_blob:
|
||||
if (!xdr_quad(xdrs, (SQUAD*) p))
|
||||
|
@ -62,6 +62,7 @@ static const TimeZoneDesc* getDesc(USHORT timeZone);
|
||||
static inline bool isOffset(USHORT timeZone);
|
||||
static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm);
|
||||
static inline SSHORT offsetZoneToDisplacement(USHORT timeZone);
|
||||
static inline USHORT displacementToOffsetZone(SSHORT displacement);
|
||||
static int parseNumber(const char*& p, const char* end);
|
||||
static void skipSpaces(const char*& p, const char* end);
|
||||
|
||||
@ -410,11 +411,28 @@ USHORT TimeZoneUtil::parseRegion(const char* str, unsigned strLen)
|
||||
}
|
||||
|
||||
// Format a time zone to string, as offset or region.
|
||||
unsigned TimeZoneUtil::format(char* buffer, size_t bufferSize, USHORT timeZone)
|
||||
unsigned TimeZoneUtil::format(char* buffer, size_t bufferSize, USHORT timeZone, bool fallback, SLONG offset)
|
||||
{
|
||||
char* p = buffer;
|
||||
|
||||
if (isOffset(timeZone))
|
||||
if (fallback)
|
||||
{
|
||||
if (offset == NO_OFFSET)
|
||||
p += fb_utils::snprintf(p, bufferSize - (p - buffer), "%s", GMT_FALLBACK);
|
||||
else
|
||||
{
|
||||
if (offset != 0)
|
||||
*p++ = offset < 0 ? '-' : '+';
|
||||
|
||||
if (offset < 0)
|
||||
offset = -offset;
|
||||
|
||||
int minutes = offset % 60;
|
||||
offset /= 60;
|
||||
p += fb_utils::snprintf(p, bufferSize - (p - buffer), "%02d:%02d", offset, minutes);
|
||||
}
|
||||
}
|
||||
else if (isOffset(timeZone))
|
||||
{
|
||||
SSHORT displacement = offsetZoneToDisplacement(timeZone);
|
||||
|
||||
@ -444,6 +462,19 @@ bool TimeZoneUtil::isValidOffset(int sign, unsigned tzh, unsigned tzm)
|
||||
|
||||
// Extracts the offsets from a offset- or region-based datetime with time zone.
|
||||
void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign, unsigned* tzh, unsigned* tzm)
|
||||
{
|
||||
SSHORT displacement;
|
||||
extractOffset(timeStampTz, &displacement);
|
||||
|
||||
*sign = displacement < 0 ? -1 : 1;
|
||||
displacement = displacement < 0 ? -displacement : displacement;
|
||||
|
||||
*tzh = displacement / 60;
|
||||
*tzm = displacement % 60;
|
||||
}
|
||||
|
||||
// Extracts the offset (+- minutes) from a offset- or region-based datetime with time zone.
|
||||
void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* offset)
|
||||
{
|
||||
SSHORT displacement;
|
||||
|
||||
@ -486,11 +517,7 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign,
|
||||
icuLib.ucalClose(icuCalendar);
|
||||
}
|
||||
|
||||
*sign = displacement < 0 ? -1 : 1;
|
||||
displacement = displacement < 0 ? -displacement : displacement;
|
||||
|
||||
*tzh = displacement / 60;
|
||||
*tzm = displacement % 60;
|
||||
*offset = displacement;
|
||||
}
|
||||
|
||||
// Converts a time-tz to a time in a given zone.
|
||||
@ -516,7 +543,7 @@ ISC_TIMESTAMP TimeZoneUtil::timeStampTzToTimeStamp(const ISC_TIMESTAMP_TZ& timeS
|
||||
|
||||
struct tm times;
|
||||
int fractions;
|
||||
decodeTimeStamp(tempTimeStampTz, false, ×, &fractions);
|
||||
decodeTimeStamp(tempTimeStampTz, false, TimeZoneUtil::NO_OFFSET, ×, &fractions);
|
||||
|
||||
return TimeStamp::encode_timestamp(×, fractions);
|
||||
}
|
||||
@ -613,7 +640,7 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
|
||||
timeStampTz.utc_timestamp.timestamp_time = ticks % TimeStamp::ISC_TICKS_PER_DAY;
|
||||
}
|
||||
|
||||
bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callbacks* cb,
|
||||
bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, SLONG gmtOffset, Callbacks* cb,
|
||||
struct tm* times, int* fractions)
|
||||
{
|
||||
bool tzLookup = true;
|
||||
@ -621,6 +648,10 @@ bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callb
|
||||
|
||||
try
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
if (gmtFallback && getenv("MISSING_ICU_EMULATION"))
|
||||
(Arg::Gds(isc_random) << "Emulating missing ICU").raise();
|
||||
#endif
|
||||
timeStampTz = cvtTimeTzToTimeStampTz(timeTz, cb);
|
||||
}
|
||||
catch (const Exception&)
|
||||
@ -628,7 +659,7 @@ bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callb
|
||||
if (gmtFallback)
|
||||
{
|
||||
tzLookup = false;
|
||||
timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE;
|
||||
timeStampTz.time_zone = displacementToOffsetZone(gmtOffset == TimeZoneUtil::NO_OFFSET ? 0 : gmtOffset);
|
||||
timeStampTz.utc_timestamp = cb->getCurrentGmtTimeStamp();
|
||||
timeStampTz.utc_timestamp.timestamp_time = timeTz.utc_time;
|
||||
}
|
||||
@ -636,11 +667,11 @@ bool TimeZoneUtil::decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callb
|
||||
throw;
|
||||
}
|
||||
|
||||
decodeTimeStamp(timeStampTz, false, times, fractions);
|
||||
decodeTimeStamp(timeStampTz, gmtFallback, gmtOffset, times, fractions);
|
||||
return tzLookup;
|
||||
}
|
||||
|
||||
bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback,
|
||||
bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback, SLONG gmtOffset,
|
||||
struct tm* times, int* fractions)
|
||||
{
|
||||
SINT64 ticks = timeStampTz.utc_timestamp.timestamp_date * TimeStamp::ISC_TICKS_PER_DAY +
|
||||
@ -658,6 +689,10 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt
|
||||
|
||||
try
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
if (gmtFallback && getenv("MISSING_ICU_EMULATION"))
|
||||
(Arg::Gds(isc_random) << "Emulating missing ICU").raise();
|
||||
#endif
|
||||
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
|
||||
|
||||
UCalendar* icuCalendar = icuLib.ucalOpen(
|
||||
@ -687,13 +722,11 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
if (gmtFallback)
|
||||
{
|
||||
icuFail = true;
|
||||
displacement = 0;
|
||||
}
|
||||
else
|
||||
if (!gmtFallback)
|
||||
throw;
|
||||
|
||||
icuFail = true;
|
||||
displacement = gmtOffset == TimeZoneUtil::NO_OFFSET ? 0 : gmtOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1037,7 +1070,7 @@ static USHORT makeFromOffset(int sign, unsigned tzh, unsigned tzm)
|
||||
status_exception::raise(Arg::Gds(isc_invalid_timezone_offset) << str);
|
||||
}
|
||||
|
||||
return (USHORT)((tzh * 60 + tzm) * sign + ONE_DAY);
|
||||
return (USHORT)displacementToOffsetZone((tzh * 60 + tzm) * sign);
|
||||
}
|
||||
|
||||
// Gets the displacement from a offset-based time zone id.
|
||||
@ -1048,6 +1081,11 @@ static inline SSHORT offsetZoneToDisplacement(USHORT timeZone)
|
||||
return (SSHORT) (int(timeZone) - ONE_DAY);
|
||||
}
|
||||
|
||||
static inline USHORT displacementToOffsetZone(SSHORT displacement)
|
||||
{
|
||||
return (USHORT)(int(displacement) + ONE_DAY);
|
||||
}
|
||||
|
||||
// Parses a integer number.
|
||||
static int parseNumber(const char*& p, const char* end)
|
||||
{
|
||||
|
@ -91,10 +91,12 @@ public:
|
||||
static USHORT parse(const char* str, unsigned strLen);
|
||||
static USHORT parseRegion(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,
|
||||
bool fallback = false, SLONG offset = NO_OFFSET);
|
||||
|
||||
static bool isValidOffset(int sign, unsigned tzh, unsigned tzm);
|
||||
|
||||
static void extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* offset);
|
||||
static void extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, int* sign, unsigned* tzh, unsigned* tzm);
|
||||
|
||||
static ISC_TIME timeTzToTime(const ISC_TIME_TZ& timeTz, USHORT toTimeZone, Callbacks* cb);
|
||||
@ -106,9 +108,10 @@ public:
|
||||
static void localTimeStampToUtc(ISC_TIMESTAMP& timeStamp, Callbacks* cb);
|
||||
static void localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz);
|
||||
|
||||
static bool decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, Callbacks* cb,
|
||||
static const SLONG NO_OFFSET = MAX_SLONG;
|
||||
static bool decodeTime(const ISC_TIME_TZ& timeTz, bool gmtFallback, SLONG gmtOffset, Callbacks* cb,
|
||||
struct tm* times, int* fractions = NULL);
|
||||
static bool decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback,
|
||||
static bool decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmtFallback, SLONG gmtOffset,
|
||||
struct tm* times, int* fractions = NULL);
|
||||
|
||||
static ISC_TIMESTAMP_TZ getCurrentSystemTimeStamp();
|
||||
|
@ -155,6 +155,11 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr,
|
||||
item->length = sizeof(ISC_TIMESTAMP_TZ);
|
||||
break;
|
||||
|
||||
case blr_ex_timestamp_tz:
|
||||
item->type = SQL_TIMESTAMP_TZ_EX;
|
||||
item->length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
break;
|
||||
|
||||
case blr_sql_date:
|
||||
item->type = SQL_TYPE_DATE;
|
||||
item->length = sizeof(SLONG);
|
||||
@ -170,6 +175,11 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr,
|
||||
item->length = sizeof(ISC_TIME_TZ);
|
||||
break;
|
||||
|
||||
case blr_ex_time_tz:
|
||||
item->type = SQL_TIME_TZ_EX;
|
||||
item->length = sizeof(ISC_TIME_TZ_EX);
|
||||
break;
|
||||
|
||||
case blr_blob2:
|
||||
item->type = SQL_BLOB;
|
||||
item->length = sizeof(ISC_QUAD);
|
||||
|
@ -1533,6 +1533,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
// Do data type by data type conversions. Not all are supported,
|
||||
// and some will drop out for additional handling.
|
||||
|
||||
dsc d;
|
||||
switch (to->dsc_dtype)
|
||||
{
|
||||
case dtype_timestamp:
|
||||
@ -1560,11 +1561,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
return;
|
||||
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
*(ISC_TIMESTAMP*) to->dsc_address =
|
||||
TimeZoneUtil::cvtTimeTzToTimeStamp(*(ISC_TIME_TZ*) from->dsc_address, cb);
|
||||
return;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
*(ISC_TIMESTAMP*) to->dsc_address =
|
||||
TimeZoneUtil::cvtTimeStampTzToTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb);
|
||||
return;
|
||||
@ -1575,6 +1578,20 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
}
|
||||
break;
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
d.makeTimestampTz((ISC_TIMESTAMP_TZ*)(to->dsc_address));
|
||||
CVT_move_common(from, &d, decSt, cb);
|
||||
TimeZoneUtil::extractOffset(*(ISC_TIMESTAMP_TZ*)(to->dsc_address),
|
||||
&((ISC_TIMESTAMP_TZ_EX*)(to->dsc_address))->ext_offset);
|
||||
return;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
d.makeTimeTz((ISC_TIME_TZ*)(to->dsc_address));
|
||||
CVT_move_common(from, &d, decSt, cb);
|
||||
TimeZoneUtil::extractOffset(TimeZoneUtil::cvtTimeTzToTimeStampTz(*(ISC_TIME_TZ*)(to->dsc_address), cb),
|
||||
&((ISC_TIME_TZ_EX*)(to->dsc_address))->ext_offset);
|
||||
return;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
switch (from->dsc_dtype)
|
||||
{
|
||||
@ -1593,11 +1610,16 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
TimeZoneUtil::cvtTimeToTimeStampTz(*(ISC_TIME*) from->dsc_address, cb);
|
||||
return;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_sql_time_tz:
|
||||
*((ISC_TIMESTAMP_TZ*) to->dsc_address) =
|
||||
TimeZoneUtil::cvtTimeTzToTimeStampTz(*(ISC_TIME_TZ*) from->dsc_address, cb);
|
||||
return;
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
*((ISC_TIMESTAMP_TZ*) to->dsc_address) = *((ISC_TIMESTAMP_TZ*) from->dsc_address);
|
||||
return;
|
||||
|
||||
case dtype_sql_date:
|
||||
*(ISC_TIMESTAMP_TZ*) to->dsc_address =
|
||||
TimeZoneUtil::cvtDateToTimeStampTz(*(GDS_DATE*) from->dsc_address, cb);
|
||||
@ -1632,6 +1654,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
return;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
*(GDS_DATE*) to->dsc_address =
|
||||
TimeZoneUtil::cvtTimeStampTzToTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb).timestamp_date;
|
||||
return;
|
||||
@ -1656,6 +1679,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
return;
|
||||
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
*(ISC_TIME*) to->dsc_address = TimeZoneUtil::cvtTimeTzToTime(*(ISC_TIME_TZ*) from->dsc_address, cb);
|
||||
return;
|
||||
|
||||
@ -1664,6 +1688,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
return;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
*(GDS_TIME*) to->dsc_address =
|
||||
TimeZoneUtil::cvtTimeStampTzToTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, cb).timestamp_time;
|
||||
return;
|
||||
@ -1698,10 +1723,15 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
return;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
*(ISC_TIME_TZ*) to->dsc_address =
|
||||
TimeZoneUtil::cvtTimeStampTzToTimeTz(*(ISC_TIMESTAMP_TZ*) from->dsc_address);
|
||||
return;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
*(ISC_TIME_TZ*) to->dsc_address = *(ISC_TIME_TZ*) from->dsc_address;
|
||||
return;
|
||||
|
||||
default:
|
||||
CVT_conversion_error(from, cb->err);
|
||||
break;
|
||||
@ -1907,8 +1937,10 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
case dtype_sql_date:
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_timestamp:
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
datetime_to_text(from, to, cb);
|
||||
return;
|
||||
|
||||
@ -2163,7 +2195,9 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
break;
|
||||
|
||||
case dtype_sql_time_tz:
|
||||
tzLookup = TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address, true, cb, ×, &fractions);
|
||||
case dtype_ex_time_tz:
|
||||
tzLookup = TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) from->dsc_address,
|
||||
true, TimeZoneUtil::NO_OFFSET, cb, ×, &fractions);
|
||||
timezone = ((ISC_TIME_TZ*) from->dsc_address)->time_zone;
|
||||
break;
|
||||
|
||||
@ -2177,8 +2211,10 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
break;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
cb->isVersion4(version4); // Used in the conversion to text some lines below.
|
||||
tzLookup = TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address, true, ×, &fractions);
|
||||
tzLookup = TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) from->dsc_address,
|
||||
true, TimeZoneUtil::NO_OFFSET, ×, &fractions);
|
||||
timezone = ((ISC_TIMESTAMP_TZ*) from->dsc_address)->time_zone;
|
||||
break;
|
||||
|
||||
@ -2196,7 +2232,7 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
|
||||
// Make a textual date for data types that include it
|
||||
|
||||
if (from->dsc_dtype != dtype_sql_time && from->dsc_dtype != dtype_sql_time_tz)
|
||||
if (!from->isTime())
|
||||
{
|
||||
if (from->dsc_dtype == dtype_sql_date || !version4)
|
||||
{
|
||||
@ -2217,14 +2253,14 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
|
||||
// Put in a space to separate date & time components
|
||||
|
||||
if ((from->dsc_dtype == dtype_timestamp || from->dsc_dtype == dtype_timestamp_tz) && !version4)
|
||||
if (from->isTimeStamp() && !version4)
|
||||
*p++ = ' ';
|
||||
|
||||
// Add the time part for data types that include it
|
||||
|
||||
if (from->dsc_dtype != dtype_sql_date)
|
||||
{
|
||||
if (from->dsc_dtype == dtype_sql_time || from->dsc_dtype == dtype_sql_time_tz || !version4)
|
||||
if (from->isTime() || !version4)
|
||||
{
|
||||
sprintf(p, "%2.2d:%2.2d:%2.2d.%4.4d",
|
||||
times.tm_hour, times.tm_min, times.tm_sec, fractions);
|
||||
@ -2240,16 +2276,10 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
p++;
|
||||
}
|
||||
|
||||
if (from->dsc_dtype == dtype_sql_time_tz || from->dsc_dtype == dtype_timestamp_tz)
|
||||
if (from->isDateTimeTz())
|
||||
{
|
||||
*p++ = ' ';
|
||||
if (tzLookup)
|
||||
p += TimeZoneUtil::format(p, sizeof(temp) - (p - temp), timezone);
|
||||
else
|
||||
{
|
||||
strncpy(p, TimeZoneUtil::GMT_FALLBACK, sizeof(temp) - (p - temp));
|
||||
p += strlen(TimeZoneUtil::GMT_FALLBACK);
|
||||
}
|
||||
p += TimeZoneUtil::format(p, sizeof(temp) - (p - temp), timezone, !tzLookup);
|
||||
}
|
||||
|
||||
// Move the text version of the date/time value into the destination
|
||||
@ -2261,7 +2291,7 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb)
|
||||
desc.dsc_ttype() = ttype_ascii;
|
||||
desc.dsc_length = (p - temp);
|
||||
|
||||
if ((from->dsc_dtype == dtype_timestamp || from->dsc_dtype == dtype_timestamp_tz) && version4)
|
||||
if (from->isTimeStamp() && version4)
|
||||
{
|
||||
// Prior to BLR Version5, when a timestamp is converted to a string it
|
||||
// is silently truncated if the destination string is not large enough
|
||||
@ -3428,8 +3458,10 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
|
||||
case dtype_sql_date:
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_timestamp:
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
case dtype_array:
|
||||
case dtype_dbkey:
|
||||
case dtype_boolean:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,7 @@ inline bool DTYPE_IS_TEXT(UCHAR d)
|
||||
|
||||
inline bool DTYPE_IS_DATE(UCHAR t)
|
||||
{
|
||||
return (t >= dtype_sql_date && t <= dtype_timestamp) || t == dtype_sql_time_tz || t == dtype_timestamp_tz;
|
||||
return (t >= dtype_sql_date && t <= dtype_timestamp) || (t >= dtype_sql_time_tz && t <= dtype_ex_timestamp_tz);
|
||||
}
|
||||
|
||||
// DTYPE_IS_BLOB includes both BLOB and ARRAY since array's are implemented over blobs.
|
||||
@ -161,13 +161,12 @@ typedef struct dsc
|
||||
|
||||
bool isDateTime() const
|
||||
{
|
||||
return (dsc_dtype >= dtype_sql_date && dsc_dtype <= dtype_timestamp) ||
|
||||
dsc_dtype == dtype_sql_time_tz || dsc_dtype == dtype_timestamp_tz;
|
||||
return DTYPE_IS_DATE(dsc_dtype);
|
||||
}
|
||||
|
||||
bool isDateTimeTz() const
|
||||
{
|
||||
return dsc_dtype == dtype_sql_time_tz || dsc_dtype == dtype_timestamp_tz;
|
||||
return dsc_dtype >= dtype_sql_time_tz && dsc_dtype <= dtype_ex_timestamp_tz;
|
||||
}
|
||||
|
||||
bool isDate() const
|
||||
@ -177,12 +176,12 @@ typedef struct dsc
|
||||
|
||||
bool isTime() const
|
||||
{
|
||||
return dsc_dtype == dtype_sql_time || dsc_dtype == dtype_sql_time_tz;
|
||||
return dsc_dtype == dtype_sql_time || dsc_dtype == dtype_sql_time_tz || dsc_dtype == dtype_ex_time_tz;
|
||||
}
|
||||
|
||||
bool isTimeStamp() const
|
||||
{
|
||||
return dsc_dtype == dtype_timestamp || dsc_dtype == dtype_timestamp_tz;
|
||||
return dsc_dtype == dtype_timestamp || dsc_dtype == dtype_timestamp_tz || dsc_dtype == dtype_ex_timestamp_tz;
|
||||
}
|
||||
|
||||
bool isDecFloat() const
|
||||
@ -423,6 +422,15 @@ typedef struct dsc
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeTimeTzEx(ISC_TIME_TZ_EX* address = NULL)
|
||||
{
|
||||
clear();
|
||||
dsc_dtype = dtype_ex_time_tz;
|
||||
dsc_length = sizeof(ISC_TIME_TZ_EX);
|
||||
dsc_scale = 0;
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeTimestamp(GDS_TIMESTAMP* address = NULL)
|
||||
{
|
||||
clear();
|
||||
@ -441,6 +449,15 @@ typedef struct dsc
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeTimestampTzEx(ISC_TIMESTAMP_TZ_EX* address = NULL)
|
||||
{
|
||||
clear();
|
||||
dsc_dtype = dtype_ex_timestamp_tz;
|
||||
dsc_length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
dsc_scale = 0;
|
||||
dsc_address = (UCHAR*) address;
|
||||
}
|
||||
|
||||
void makeVarying(USHORT length, USHORT ttype, UCHAR* address = NULL)
|
||||
{
|
||||
clear();
|
||||
|
@ -204,6 +204,7 @@ static const TOK tokens[] =
|
||||
{TOK_EXISTS, "EXISTS", false},
|
||||
{TOK_EXIT, "EXIT", true},
|
||||
{TOK_EXP, "EXP", true},
|
||||
{TOK_EXTENDED, "EXTENDED", true},
|
||||
{TOK_EXTERNAL, "EXTERNAL", false},
|
||||
{TOK_EXTRACT, "EXTRACT", false},
|
||||
{TOK_FALSE, "FALSE", false},
|
||||
|
@ -1554,6 +1554,10 @@ UCHAR sqlTypeToDscType(SSHORT sqlType)
|
||||
return dtype_sql_time_tz;
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
return dtype_timestamp_tz;
|
||||
case SQL_TIME_TZ_EX:
|
||||
return dtype_ex_time_tz;
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
return dtype_ex_timestamp_tz;
|
||||
default:
|
||||
return dtype_unknown;
|
||||
}
|
||||
|
@ -250,6 +250,16 @@ bool_t xdr_datum( XDR* xdrs, const dsc* desc, UCHAR* buffer)
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
fb_assert(desc->dsc_length >= sizeof(SLONG) + 2 * sizeof(SSHORT));
|
||||
if (!xdr_long(xdrs, reinterpret_cast<SLONG*>(p)))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, reinterpret_cast<SSHORT*>(p + sizeof(SLONG))))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, reinterpret_cast<SSHORT*>(p + sizeof(SLONG) + sizeof(SSHORT))))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
fb_assert(desc->dsc_length >= sizeof(float));
|
||||
if (!xdr_float(xdrs, reinterpret_cast<float*>(p)))
|
||||
@ -298,6 +308,18 @@ bool_t xdr_datum( XDR* xdrs, const dsc* desc, UCHAR* buffer)
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(desc->dsc_length >= 2 * sizeof(SLONG) + 2 * sizeof(SSHORT));
|
||||
if (!xdr_long(xdrs, &((SLONG*) p)[0]))
|
||||
return FALSE;
|
||||
if (!xdr_long(xdrs, &((SLONG*) p)[1]))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, reinterpret_cast<SSHORT*>(p + 2 * sizeof(SLONG))))
|
||||
return FALSE;
|
||||
if (!xdr_short(xdrs, reinterpret_cast<SSHORT*>(p + 2 * sizeof(SLONG) + sizeof(SSHORT))))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case dtype_int64:
|
||||
fb_assert(desc->dsc_length >= sizeof(SINT64));
|
||||
if (!xdr_hyper(xdrs, reinterpret_cast<SINT64*>(p)))
|
||||
|
@ -639,6 +639,11 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(false);
|
||||
ERRD_post(Arg::Gds(isc_expression_eval_err));
|
||||
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_sql_date:
|
||||
@ -928,6 +933,11 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(false);
|
||||
ERRD_post(Arg::Gds(isc_expression_eval_err));
|
||||
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_sql_date:
|
||||
@ -1229,6 +1239,11 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(false);
|
||||
ERRD_post(Arg::Gds(isc_expression_eval_err));
|
||||
|
||||
case dtype_sql_date:
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
@ -1518,6 +1533,11 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(false);
|
||||
ERRD_post(Arg::Gds(isc_expression_eval_err));
|
||||
|
||||
case dtype_timestamp:
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_sql_date:
|
||||
@ -2535,6 +2555,11 @@ dsc* ArithmeticNode::addDateTime(thread_db* tdbb, const dsc* desc, impure_value*
|
||||
ERR_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_invalid_type_datetime_op));
|
||||
break;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
fb_assert(false);
|
||||
ERRD_post(Arg::Gds(isc_expression_eval_err));
|
||||
|
||||
case dtype_timestamp:
|
||||
case dtype_timestamp_tz:
|
||||
default:
|
||||
@ -5463,7 +5488,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
case blr_extract_second:
|
||||
case blr_extract_millisecond:
|
||||
TimeZoneUtil::decodeTime(*(ISC_TIME_TZ*) value->dsc_address,
|
||||
false, &EngineCallbacks::instance, ×, &fractions);
|
||||
false, TimeZoneUtil::NO_OFFSET, &EngineCallbacks::instance, ×, &fractions);
|
||||
break;
|
||||
|
||||
case blr_extract_timezone_hour:
|
||||
@ -5523,7 +5548,8 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
break;
|
||||
|
||||
default:
|
||||
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, false, ×, &fractions);
|
||||
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) value->dsc_address, false, TimeZoneUtil::NO_OFFSET,
|
||||
×, &fractions);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1364,3 +1364,19 @@ void Parser::yyabandon(const Position& position, SLONG sql_code, const Arg::Stat
|
||||
Arg::Gds(isc_dsql_line_col_error) <<
|
||||
Arg::Num(position.firstLine) << Arg::Num(position.firstColumn));
|
||||
}
|
||||
|
||||
void Parser::checkTimeDialect()
|
||||
{
|
||||
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
}
|
||||
|
@ -354,6 +354,8 @@ private:
|
||||
return clause.hasData();
|
||||
}
|
||||
|
||||
void checkTimeDialect();
|
||||
|
||||
// start - defined in btyacc_fb.ske
|
||||
private:
|
||||
static void yySCopy(YYSTYPE* to, YYSTYPE* from, int size);
|
||||
|
@ -62,7 +62,9 @@ const USHORT blr_dtypes[] = {
|
||||
blr_dec128, // dtype_dec128
|
||||
blr_int128, // dtype_int128
|
||||
blr_sql_time_tz, // dtype_sql_time_tz
|
||||
blr_timestamp_tz // dtype_timestamp_tz
|
||||
blr_timestamp_tz, // dtype_timestamp_tz
|
||||
blr_ex_time_tz, // dtype_ex_time_tz
|
||||
blr_ex_timestamp_tz // dtype_ex_timestamp_tz
|
||||
};
|
||||
|
||||
bool DDL_ids(const Jrd::DsqlCompilerScratch*);
|
||||
|
@ -322,16 +322,17 @@ public:
|
||||
// values used in fld_flags
|
||||
|
||||
enum fld_flags_vals {
|
||||
FLD_computed = 1,
|
||||
FLD_national = 2, // field uses NATIONAL character set
|
||||
FLD_nullable = 4,
|
||||
FLD_system = 8,
|
||||
FLD_has_len = 16,
|
||||
FLD_has_chset = 32,
|
||||
FLD_has_scale = 64,
|
||||
FLD_legacy = 128,
|
||||
FLD_native = 256,
|
||||
FLD_has_sub = 512
|
||||
FLD_computed = 0x1,
|
||||
FLD_national = 0x2, // field uses NATIONAL character set
|
||||
FLD_nullable = 0x4,
|
||||
FLD_system = 0x8,
|
||||
FLD_has_len = 0x10,
|
||||
FLD_has_chset = 0x20,
|
||||
FLD_has_scale = 0x40,
|
||||
FLD_has_sub = 0x80,
|
||||
FLD_legacy = 0x100,
|
||||
FLD_native = 0x200,
|
||||
FLD_extended = 0x400
|
||||
};
|
||||
|
||||
//! Stored Procedure block
|
||||
|
@ -607,6 +607,7 @@ using namespace Firebird;
|
||||
%token <metaNamePtr> DEFINER
|
||||
%token <metaNamePtr> EXCESS
|
||||
%token <metaNamePtr> EXCLUDE
|
||||
%token <metaNamePtr> EXTENDED
|
||||
%token <metaNamePtr> FIRST_DAY
|
||||
%token <metaNamePtr> FOLLOWING
|
||||
%token <metaNamePtr> HEX_DECODE
|
||||
@ -4686,56 +4687,39 @@ non_charset_simple_type
|
||||
$$->dtype = dtype_sql_date;
|
||||
$$->length = sizeof(ULONG);
|
||||
}
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| TIME without_time_zone_opt
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
|
||||
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
checkTimeDialect();
|
||||
$$->dtype = dtype_sql_time;
|
||||
$$->length = sizeof(SLONG);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| TIME WITH TIME ZONE
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
|
||||
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) <<
|
||||
Arg::Str("TIME"));
|
||||
}
|
||||
checkTimeDialect();
|
||||
$$->dtype = dtype_sql_time_tz;
|
||||
$$->length = sizeof(ISC_TIME_TZ);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| TIMESTAMP without_time_zone_opt
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->dtype = dtype_timestamp;
|
||||
$$->length = sizeof(GDS_TIMESTAMP);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| TIMESTAMP WITH TIME ZONE
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->dtype = dtype_timestamp_tz;
|
||||
$$->length = sizeof(ISC_TIMESTAMP_TZ);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| BOOLEAN
|
||||
{
|
||||
@ -5303,14 +5287,17 @@ set_bind
|
||||
%type <legacyField> set_bind_from
|
||||
set_bind_from
|
||||
: bind_type
|
||||
| TIME ZONE
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->dtype = dtype_timestamp_tz;
|
||||
$$->length = 0;
|
||||
}
|
||||
;
|
||||
|
||||
%type <legacyField> bind_type
|
||||
bind_type
|
||||
: non_array_type
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| varying_keyword
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
@ -5335,8 +5322,29 @@ set_bind_to
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->flags = FLD_native;
|
||||
}
|
||||
| EXTENDED
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->flags = FLD_extended;
|
||||
}
|
||||
| EXTENDED TIME WITH TIME ZONE
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
checkTimeDialect();
|
||||
$$->dtype = dtype_ex_time_tz;
|
||||
$$->length = sizeof(ISC_TIME_TZ_EX);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
| EXTENDED TIMESTAMP WITH TIME ZONE
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
$$->dtype = dtype_ex_timestamp_tz;
|
||||
$$->length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
$$->flags |= FLD_has_len;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
%type decfloat_traps_list_opt(<setDecFloatTrapsNode>)
|
||||
decfloat_traps_list_opt($setDecFloatTrapsNode)
|
||||
: // nothing
|
||||
@ -8859,6 +8867,7 @@ non_reserved_word
|
||||
| DEFINER
|
||||
| EXCESS
|
||||
| EXCLUDE
|
||||
| EXTENDED
|
||||
| FIRST_DAY
|
||||
| FOLLOWING
|
||||
| HEX_DECODE
|
||||
|
@ -32,6 +32,8 @@ typedef ISC_TIME;
|
||||
typedef ISC_TIMESTAMP;
|
||||
typedef ISC_TIME_TZ;
|
||||
typedef ISC_TIMESTAMP_TZ;
|
||||
typedef ISC_TIME_TZ_EX;
|
||||
typedef ISC_TIMESTAMP_TZ_EX;
|
||||
typedef FB_DEC16;
|
||||
typedef FB_DEC34;
|
||||
typedef FB_I128;
|
||||
@ -1114,6 +1116,10 @@ version: // 3.0 => 4.0 Alpha1
|
||||
|
||||
version: // 4.0 Beta1 => 4.0 Beta2
|
||||
Int128 getInt128(Status status);
|
||||
void decodeTimeTzEx(Status status, const ISC_TIME_TZ_EX* timeTz, uint* hours, uint* minutes, uint* seconds,
|
||||
uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer);
|
||||
void decodeTimeStampTzEx(Status status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, uint* year, uint* month, uint* day,
|
||||
uint* hours, uint* minutes, uint* seconds, uint* fractions, uint timeZoneBufferLength, string timeZoneBuffer);
|
||||
}
|
||||
|
||||
interface OffsetsCallback : Versioned
|
||||
|
@ -4082,6 +4082,8 @@ namespace Firebird
|
||||
void (CLOOP_CARG *encodeTimeTz)(IUtil* self, IStatus* status, ISC_TIME_TZ* timeTz, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) throw();
|
||||
void (CLOOP_CARG *encodeTimeStampTz)(IUtil* self, IStatus* status, ISC_TIMESTAMP_TZ* timeStampTz, unsigned year, unsigned month, unsigned day, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) throw();
|
||||
IInt128* (CLOOP_CARG *getInt128)(IUtil* self, IStatus* status) throw();
|
||||
void (CLOOP_CARG *decodeTimeTzEx)(IUtil* self, IStatus* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) throw();
|
||||
void (CLOOP_CARG *decodeTimeStampTzEx)(IUtil* self, IStatus* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -4304,6 +4306,32 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> void decodeTimeTzEx(StatusType* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
if (cloopVTable->version < 4)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 4);
|
||||
StatusType::checkException(status);
|
||||
return;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->decodeTimeTzEx(this, status, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> void decodeTimeStampTzEx(StatusType* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
if (cloopVTable->version < 4)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 4);
|
||||
StatusType::checkException(status);
|
||||
return;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->decodeTimeStampTzEx(this, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
};
|
||||
|
||||
class IOffsetsCallback : public IVersioned
|
||||
@ -14472,6 +14500,8 @@ namespace Firebird
|
||||
this->encodeTimeTz = &Name::cloopencodeTimeTzDispatcher;
|
||||
this->encodeTimeStampTz = &Name::cloopencodeTimeStampTzDispatcher;
|
||||
this->getInt128 = &Name::cloopgetInt128Dispatcher;
|
||||
this->decodeTimeTzEx = &Name::cloopdecodeTimeTzExDispatcher;
|
||||
this->decodeTimeStampTzEx = &Name::cloopdecodeTimeStampTzExDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -14785,6 +14815,34 @@ namespace Firebird
|
||||
return static_cast<IInt128*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdecodeTimeTzExDispatcher(IUtil* self, IStatus* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::decodeTimeTzEx(&status2, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdecodeTimeStampTzExDispatcher(IUtil* self, IStatus* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::decodeTimeStampTzEx(&status2, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IUtil> > >
|
||||
@ -14822,6 +14880,8 @@ namespace Firebird
|
||||
virtual void encodeTimeTz(StatusType* status, ISC_TIME_TZ* timeTz, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) = 0;
|
||||
virtual void encodeTimeStampTz(StatusType* status, ISC_TIMESTAMP_TZ* timeStampTz, unsigned year, unsigned month, unsigned day, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) = 0;
|
||||
virtual IInt128* getInt128(StatusType* status) = 0;
|
||||
virtual void decodeTimeTzEx(StatusType* status, const ISC_TIME_TZ_EX* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0;
|
||||
virtual void decodeTimeStampTzEx(StatusType* status, const ISC_TIMESTAMP_TZ_EX* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -167,6 +167,10 @@
|
||||
builder->setType(status, index, SQL_TIME_TZ); \
|
||||
builder->setLength(status, index, sizeof(::Firebird::FbTimeTz));
|
||||
|
||||
#define FB__META_FB_TIME_TZ_EX \
|
||||
builder->setType(status, index, SQL_TIME_TZ_EX); \
|
||||
builder->setLength(status, index, sizeof(::Firebird::FbTimeTzEx));
|
||||
|
||||
#define FB__META_FB_TIMESTAMP \
|
||||
builder->setType(status, index, SQL_TIMESTAMP); \
|
||||
builder->setLength(status, index, sizeof(::Firebird::FbTimestamp));
|
||||
@ -175,6 +179,10 @@
|
||||
builder->setType(status, index, SQL_TIMESTAMP_TZ); \
|
||||
builder->setLength(status, index, sizeof(::Firebird::FbTimestampTz));
|
||||
|
||||
#define FB__META_FB_TIMESTAMP_TZ_EX \
|
||||
builder->setType(status, index, SQL_TIMESTAMP_TZ_EX); \
|
||||
builder->setLength(status, index, sizeof(::Firebird::FbTimestampTzEx));
|
||||
|
||||
#define FB__META_FB_CHAR(len) \
|
||||
builder->setType(status, index, SQL_TEXT); \
|
||||
builder->setLength(status, index, len);
|
||||
@ -214,8 +222,10 @@
|
||||
#define FB__TYPE_FB_DATE ::Firebird::FbDate
|
||||
#define FB__TYPE_FB_TIME ::Firebird::FbTime
|
||||
#define FB__TYPE_FB_TIME_TZ ::Firebird::FbTimeTz
|
||||
#define FB__TYPE_FB_TIME_TZ_EX ::Firebird::FbTimeTzEx
|
||||
#define FB__TYPE_FB_TIMESTAMP ::Firebird::FbTimestamp
|
||||
#define FB__TYPE_FB_TIMESTAMP_TZ ::Firebird::FbTimestampTz
|
||||
#define FB__TYPE_FB_TIMESTAMP_TZ_EX ::Firebird::FbTimestampTzEx
|
||||
#define FB__TYPE_FB_CHAR(len) ::Firebird::FbChar<(len)>
|
||||
#define FB__TYPE_FB_VARCHAR(len) ::Firebird::FbVarChar<(len)>
|
||||
#define FB__TYPE_FB_INTL_CHAR(len, charSet) ::Firebird::FbChar<(len)>
|
||||
@ -407,6 +417,32 @@ public:
|
||||
ISC_USHORT timeZone;
|
||||
};
|
||||
|
||||
// This class has memory layout identical to ISC_TIME_TZ_EX.
|
||||
class FbTimeTzEx
|
||||
{
|
||||
public:
|
||||
FbTimeTzEx& operator=(ISC_TIME_TZ_EX& val)
|
||||
{
|
||||
*(this) = *(FbTimeTzEx*) &val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator ISC_TIME_TZ_EX&()
|
||||
{
|
||||
return *(ISC_TIME_TZ_EX*) this;
|
||||
}
|
||||
|
||||
operator const ISC_TIME_TZ_EX&() const
|
||||
{
|
||||
return *(ISC_TIME_TZ_EX*) this;
|
||||
}
|
||||
|
||||
public:
|
||||
FbTime utcTime;
|
||||
ISC_USHORT timeZone;
|
||||
ISC_SHORT extOffset;
|
||||
};
|
||||
|
||||
// This class has memory layout identical to ISC_TIMESTAMP.
|
||||
class FbTimestamp
|
||||
{
|
||||
@ -457,6 +493,32 @@ public:
|
||||
ISC_USHORT timeZone;
|
||||
};
|
||||
|
||||
// This class has memory layout identical to ISC_TIMESTAMP_TZ_EX.
|
||||
class FbTimestampTzEx
|
||||
{
|
||||
public:
|
||||
FbTimestampTzEx& operator=(ISC_TIMESTAMP_TZ_EX& val)
|
||||
{
|
||||
*(this) = *(FbTimestampTzEx*) &val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator ISC_TIMESTAMP_TZ_EX&()
|
||||
{
|
||||
return *(ISC_TIMESTAMP_TZ_EX*) this;
|
||||
}
|
||||
|
||||
operator const ISC_TIMESTAMP_TZ_EX&() const
|
||||
{
|
||||
return *(ISC_TIMESTAMP_TZ_EX*) this;
|
||||
}
|
||||
|
||||
public:
|
||||
FbTimestamp utcTimestamp;
|
||||
ISC_USHORT timeZone;
|
||||
ISC_SHORT extOffset;
|
||||
};
|
||||
|
||||
class MessageDesc
|
||||
{
|
||||
public:
|
||||
|
@ -72,6 +72,8 @@
|
||||
#define blr_int128 (unsigned char)26
|
||||
#define blr_sql_time_tz (unsigned char)28
|
||||
#define blr_timestamp_tz (unsigned char)29
|
||||
#define blr_ex_time_tz (unsigned char)30
|
||||
#define blr_ex_timestamp_tz (unsigned char)31
|
||||
|
||||
// first sub parameter for blr_domain_name[2]
|
||||
#define blr_domain_type_of (unsigned char)0
|
||||
|
@ -66,7 +66,9 @@
|
||||
#define dtype_int128 24
|
||||
#define dtype_sql_time_tz 25
|
||||
#define dtype_timestamp_tz 26
|
||||
#define DTYPE_TYPE_MAX 27
|
||||
#define dtype_ex_time_tz 27
|
||||
#define dtype_ex_timestamp_tz 28
|
||||
#define DTYPE_TYPE_MAX 29
|
||||
|
||||
#define ISC_TIME_SECONDS_PRECISION 10000
|
||||
#define ISC_TIME_SECONDS_PRECISION_SCALE (-4)
|
||||
|
@ -78,6 +78,8 @@ typedef struct
|
||||
#define SQL_TYPE_TIME 560
|
||||
#define SQL_TYPE_DATE 570
|
||||
#define SQL_INT64 580
|
||||
#define SQL_TIMESTAMP_TZ_EX 32748
|
||||
#define SQL_TIME_TZ_EX 32750
|
||||
#define SQL_INT128 32752
|
||||
#define SQL_TIMESTAMP_TZ 32754
|
||||
#define SQL_TIME_TZ 32756
|
||||
|
@ -160,6 +160,13 @@ typedef struct
|
||||
ISC_USHORT time_zone;
|
||||
} ISC_TIME_TZ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISC_TIME utc_time;
|
||||
ISC_USHORT time_zone;
|
||||
ISC_SHORT ext_offset;
|
||||
} ISC_TIME_TZ_EX;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISC_DATE timestamp_date;
|
||||
@ -172,6 +179,13 @@ typedef struct
|
||||
ISC_USHORT time_zone;
|
||||
} ISC_TIMESTAMP_TZ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISC_TIMESTAMP utc_timestamp;
|
||||
ISC_USHORT time_zone;
|
||||
ISC_SHORT ext_offset;
|
||||
} ISC_TIMESTAMP_TZ_EX;
|
||||
|
||||
/*******************************************************************/
|
||||
/* Blob Id support */
|
||||
/*******************************************************************/
|
||||
|
@ -2476,6 +2476,27 @@ static processing_state add_row(TEXT* tabname)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIME_TZ_EX:
|
||||
case SQL_TIME_TZ:
|
||||
{
|
||||
Firebird::string tmp(lastInputLine, length);
|
||||
unsigned hours, minutes, seconds;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
fb_assert(TimeZoneUtil::MAX_SIZE - 1 == 32);
|
||||
if (3 > sscanf(tmp.c_str(), "%u:%u:%u %32s", &hours, &minutes, &seconds, timeZone))
|
||||
{
|
||||
IUTILS_msg_get(TIME_ERR, txt, SafeArg() << tmp.c_str());
|
||||
STDERROUT(txt); // Bad time %s\n
|
||||
done = true;
|
||||
}
|
||||
|
||||
Firebird::UtilInterfacePtr()->encodeTimeTz(fbStatus,
|
||||
(ISC_TIME_TZ*) datap, hours, minutes, seconds, 0, timeZone);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP:
|
||||
if (6 <= sscanf(lastInputLine, "%d/%d/%d %d:%d:%d.%4s",
|
||||
×.tm_year, ×.tm_mon, ×.tm_mday,
|
||||
@ -2516,6 +2537,29 @@ static processing_state add_row(TEXT* tabname)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
{
|
||||
Firebird::string tmp(lastInputLine, length);
|
||||
unsigned year, month, day;
|
||||
unsigned hours, minutes, seconds, fractions;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
fb_assert(TimeZoneUtil::MAX_SIZE - 1 == 32);
|
||||
if (7 > sscanf(tmp.c_str(), "%u-%u-%u %u:%u:%u.%u %32s", &year, &month, &day,
|
||||
&hours, &minutes, &seconds, &fractions, timeZone))
|
||||
{
|
||||
IUTILS_msg_get(TIMESTAMP_ERR, txt, SafeArg() << tmp.c_str());
|
||||
STDERROUT(txt); // Bad time %s\n
|
||||
done = true;
|
||||
}
|
||||
|
||||
Firebird::UtilInterfacePtr()->encodeTimeStampTz(fbStatus,
|
||||
(ISC_TIMESTAMP_TZ*) datap, year, month, day, hours, minutes, seconds, fractions, timeZone);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TEXT:
|
||||
case SQL_VARYING:
|
||||
varLength = msg->getLength(fbStatus, i);
|
||||
@ -3270,6 +3314,27 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIME_TZ_EX:
|
||||
case SQL_TIME_TZ:
|
||||
{
|
||||
Firebird::string tmp(lastPos, length);
|
||||
unsigned hours, minutes, seconds;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
fb_assert(TimeZoneUtil::MAX_SIZE - 1 == 32);
|
||||
if (3 > sscanf(tmp.c_str(), "%u:%u:%u %32s", &hours, &minutes, &seconds, timeZone))
|
||||
{
|
||||
IUTILS_msg_get(TIME_ERR, msg, SafeArg() << tmp.c_str());
|
||||
STDERROUT(msg); // Bad time %s\n
|
||||
done = true;
|
||||
}
|
||||
|
||||
Firebird::UtilInterfacePtr()->encodeTimeTz(fbStatus,
|
||||
(ISC_TIME_TZ*) datap, hours, minutes, seconds, 0, timeZone);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP:
|
||||
if (6 <= sscanf(lastPos, "%d-%d-%d %d:%d:%d.%4s",
|
||||
×.tm_year, ×.tm_mon, ×.tm_mday,
|
||||
@ -3311,6 +3376,29 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
{
|
||||
Firebird::string tmp(lastPos, length);
|
||||
unsigned year, month, day;
|
||||
unsigned hours, minutes, seconds, fractions;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
fb_assert(TimeZoneUtil::MAX_SIZE - 1 == 32);
|
||||
if (7 > sscanf(tmp.c_str(), "%u-%u-%u %u:%u:%u.%u %32s", &year, &month, &day,
|
||||
&hours, &minutes, &seconds, &fractions, timeZone))
|
||||
{
|
||||
IUTILS_msg_get(TIMESTAMP_ERR, msg, SafeArg() << tmp.c_str());
|
||||
STDERROUT(msg); // Bad time %s\n
|
||||
done = true;
|
||||
}
|
||||
|
||||
Firebird::UtilInterfacePtr()->encodeTimeStampTz(fbStatus,
|
||||
(ISC_TIMESTAMP_TZ*) datap, year, month, day, hours, minutes, seconds, fractions, timeZone);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TEXT:
|
||||
case SQL_VARYING:
|
||||
varLength = message->getLength(fbStatus, i);
|
||||
@ -7563,12 +7651,21 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
|
||||
}
|
||||
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
{
|
||||
unsigned year, month, day, hours, minutes, seconds, fractions;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
|
||||
if (dtype == SQL_TIMESTAMP_TZ)
|
||||
{
|
||||
Firebird::UtilInterfacePtr()->decodeTimeStampTz(fbStatus, var->value.asDateTimeTz,
|
||||
&year, &month, &day, &hours, &minutes, &seconds, &fractions, sizeof(timeZone), timeZone);
|
||||
}
|
||||
else
|
||||
{
|
||||
Firebird::UtilInterfacePtr()->decodeTimeStampTzEx(fbStatus, var->value.asDateTimeTzEx,
|
||||
&year, &month, &day, &hours, &minutes, &seconds, &fractions, sizeof(timeZone), timeZone);
|
||||
}
|
||||
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
return ps_ERR;
|
||||
@ -7602,12 +7699,21 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
|
||||
}
|
||||
|
||||
case SQL_TIME_TZ:
|
||||
case SQL_TIME_TZ_EX:
|
||||
{
|
||||
unsigned hours, minutes, seconds, fractions;
|
||||
char timeZone[TimeZoneUtil::MAX_SIZE];
|
||||
|
||||
if (dtype == SQL_TIME_TZ)
|
||||
{
|
||||
Firebird::UtilInterfacePtr()->decodeTimeTz(fbStatus, var->value.asTimeTz, &hours, &minutes, &seconds,
|
||||
&fractions, sizeof(timeZone), timeZone);
|
||||
}
|
||||
else
|
||||
{
|
||||
Firebird::UtilInterfacePtr()->decodeTimeTzEx(fbStatus, var->value.asTimeTzEx, &hours, &minutes, &seconds,
|
||||
&fractions, sizeof(timeZone), timeZone);
|
||||
}
|
||||
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
return ps_ERR;
|
||||
@ -8277,12 +8383,14 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns
|
||||
disp_length = DATE_ONLY_LEN;
|
||||
break;
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
disp_length = DATETIME_TZ_LEN;
|
||||
break;
|
||||
case SQL_TYPE_TIME:
|
||||
disp_length = TIME_ONLY_LEN;
|
||||
break;
|
||||
case SQL_TIME_TZ:
|
||||
case SQL_TIME_TZ_EX:
|
||||
disp_length = TIME_TZ_ONLY_LEN;
|
||||
break;
|
||||
case SQL_TYPE_DATE:
|
||||
@ -8990,12 +9098,16 @@ static const char* sqltype_to_string(unsigned sqltype)
|
||||
return "TIMESTAMP";
|
||||
case SQL_TIMESTAMP_TZ:
|
||||
return "TIMESTAMP WITH TIME ZONE";
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
return "EXTENDED TIMESTAMP WITH TIME ZONE";
|
||||
case SQL_TYPE_DATE:
|
||||
return "SQL DATE";
|
||||
case SQL_TYPE_TIME:
|
||||
return "TIME";
|
||||
case SQL_TIME_TZ:
|
||||
return "TIME WITH TIME ZONE";
|
||||
case SQL_TIME_TZ_EX:
|
||||
return "EXTENDED TIME WITH TIME ZONE";
|
||||
case SQL_BLOB:
|
||||
return "BLOB";
|
||||
case SQL_ARRAY:
|
||||
|
@ -328,6 +328,8 @@ static const sqltypes Column_types[] = {
|
||||
{blr_int128, "INT64"},
|
||||
{blr_sql_time_tz, "TIME WITH TIME ZONE"}, // keyword
|
||||
{blr_timestamp_tz, "TIMESTAMP WITH TIME ZONE"}, // keyword
|
||||
{blr_ex_time_tz, "TIME WITH TIME ZONE"},
|
||||
{blr_ex_timestamp_tz, "TIMESTAMP WITH TIME ZONE"},
|
||||
{0, ""}
|
||||
};
|
||||
|
||||
@ -464,8 +466,10 @@ struct IsqlVar
|
||||
{
|
||||
ISC_TIMESTAMP* asDateTime;
|
||||
ISC_TIMESTAMP_TZ* asDateTimeTz;
|
||||
ISC_TIMESTAMP_TZ_EX* asDateTimeTzEx;
|
||||
ISC_TIME* asTime;
|
||||
ISC_TIME_TZ* asTimeTz;
|
||||
ISC_TIME_TZ_EX* asTimeTzEx;
|
||||
ISC_DATE* asDate;
|
||||
SSHORT* asSmallint;
|
||||
SLONG* asInteger;
|
||||
|
@ -37,7 +37,7 @@ using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
|
||||
static const USHORT FROM_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | FLD_has_sub;
|
||||
static const USHORT TO_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | FLD_legacy | FLD_native | FLD_has_sub;
|
||||
static const USHORT TO_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | FLD_legacy | FLD_native | FLD_has_sub | FLD_extended;
|
||||
|
||||
bool CoercionArray::coerce(dsc* d, unsigned startItem) const
|
||||
{
|
||||
@ -88,6 +88,14 @@ void CoercionRule::setRule(const TypeClause* from, const TypeClause *to)
|
||||
if (toMask & (FLD_native | FLD_legacy))
|
||||
return;
|
||||
|
||||
// Extending timezone info
|
||||
if (toMask & FLD_extended)
|
||||
{
|
||||
if (fromDsc.isDateTimeTz())
|
||||
return;
|
||||
raiseError();
|
||||
}
|
||||
|
||||
// Exceptions - enable blob2blob & blob2string casts
|
||||
if ((toDsc.dsc_dtype == dtype_blob && fromDsc.isText()) ||
|
||||
(fromDsc.dsc_dtype == dtype_blob && toDsc.isText()) ||
|
||||
@ -154,7 +162,7 @@ bool CoercionRule::match(const dsc* d) const
|
||||
{
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
if (d->dsc_dtype == dtype_dec64 || d->dsc_dtype == dtype_dec128)
|
||||
if (DTYPE_IS_DECFLOAT(d->dsc_dtype))
|
||||
return true;
|
||||
break;
|
||||
|
||||
@ -165,6 +173,12 @@ bool CoercionRule::match(const dsc* d) const
|
||||
if (d->isExact() && (fromMask & FLD_has_sub) && (d->dsc_sub_type != dsc_num_type_none))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_sql_time_tz:
|
||||
if (d->isDateTimeTz())
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,19 +212,19 @@ bool CoercionRule::coerce(dsc* d) const
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
d->dsc_dtype = dtype_double;
|
||||
d->dsc_length = 8;
|
||||
d->dsc_length = sizeof(double);
|
||||
break;
|
||||
case dtype_sql_time_tz:
|
||||
d->dsc_dtype = dtype_sql_time;
|
||||
d->dsc_length = 4;
|
||||
d->dsc_length = sizeof(ISC_TIME);
|
||||
break;
|
||||
case dtype_timestamp_tz:
|
||||
d->dsc_dtype = dtype_timestamp;
|
||||
d->dsc_length = 8;
|
||||
d->dsc_length = sizeof(ISC_TIMESTAMP);
|
||||
break;
|
||||
case dtype_int128:
|
||||
d->dsc_dtype = dtype_int64;
|
||||
d->dsc_length = 8;
|
||||
d->dsc_length = sizeof(SINT64);
|
||||
break;
|
||||
case dtype_boolean:
|
||||
d->dsc_dtype = dtype_text;
|
||||
@ -224,7 +238,30 @@ bool CoercionRule::coerce(dsc* d) const
|
||||
return found;
|
||||
}
|
||||
|
||||
// Final pass - order is important
|
||||
// extending time zone
|
||||
if (toMask & FLD_extended)
|
||||
{
|
||||
bool found = true;
|
||||
|
||||
switch(d->dsc_dtype)
|
||||
{
|
||||
case dtype_timestamp_tz:
|
||||
d->dsc_dtype = dtype_ex_timestamp_tz;
|
||||
d->dsc_length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
break;
|
||||
case dtype_sql_time_tz:
|
||||
d->dsc_dtype = dtype_ex_time_tz;
|
||||
d->dsc_length = sizeof(ISC_TIME_TZ_EX);
|
||||
break;
|
||||
default:
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// final pass - order is important
|
||||
|
||||
// length
|
||||
if (toMask & FLD_has_len)
|
||||
|
@ -3831,7 +3831,8 @@ dsc* evlFirstLastDay(thread_db* tdbb, const SysFunction* function, const NestVal
|
||||
break;
|
||||
|
||||
case dtype_timestamp_tz:
|
||||
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, false, ×, &fractions);
|
||||
TimeZoneUtil::decodeTimeStamp(*(ISC_TIMESTAMP_TZ*) valueDsc->dsc_address, false, TimeZoneUtil::NO_OFFSET,
|
||||
×, &fractions);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -75,7 +75,9 @@ static const USHORT gds_cvt_blr_dtype[DTYPE_BLR_MAX + 1] =
|
||||
dtype_double, /* blr_double == 27 */
|
||||
dtype_sql_time_tz, /* blr_sql_time_tz == 28 */
|
||||
dtype_timestamp_tz, /* blr_timestamp_tz == 29 */
|
||||
0, 0, 0, 0, 0,
|
||||
dtype_ex_time_tz, /* blr_ex_time_tz == 30 */
|
||||
dtype_ex_timestamp_tz, /* blr_ex_timestamp_tz == 31 */
|
||||
0, 0, 0,
|
||||
dtype_timestamp, /* blr_timestamp == 35 */
|
||||
0,
|
||||
dtype_varying, /* blr_varying == 37 */
|
||||
@ -114,7 +116,9 @@ static const USHORT type_alignments[DTYPE_TYPE_MAX] =
|
||||
sizeof(Firebird::Decimal64),/* dtype_dec128 */
|
||||
sizeof(Firebird::Decimal64),/* dtype_int128 */
|
||||
sizeof(GDS_TIME), /* dtype_sql_time_tz */
|
||||
sizeof(GDS_DATE) /* dtype_timestamp_tz */
|
||||
sizeof(GDS_DATE), /* dtype_timestamp_tz */
|
||||
sizeof(GDS_TIME), /* dtype_ex_time_tz */
|
||||
sizeof(GDS_DATE) /* dtype_ex_timestamp_tz */
|
||||
};
|
||||
|
||||
static const USHORT type_lengths[DTYPE_TYPE_MAX] =
|
||||
@ -139,13 +143,15 @@ static const USHORT type_lengths[DTYPE_TYPE_MAX] =
|
||||
sizeof(ISC_QUAD), /* dtype_blob */
|
||||
sizeof(ISC_QUAD), /* dtype_array */
|
||||
sizeof(SINT64), /* dtype_int64 */
|
||||
sizeof(RecordNumber::Packed),/*dtype_dbkey */
|
||||
sizeof(RecordNumber::Packed), /*dtype_dbkey */
|
||||
sizeof(UCHAR), /* dtype_boolean */
|
||||
sizeof(Firebird::Decimal64),/* dtype_dec64 */
|
||||
sizeof(Firebird::Decimal128),/*dtype_dec128 */
|
||||
sizeof(Firebird::Decimal64), /* dtype_dec64 */
|
||||
sizeof(Firebird::Decimal128), /*dtype_dec128 */
|
||||
sizeof(Firebird::Int128), /* dtype_int128 */
|
||||
sizeof(ISC_TIME_TZ), /* dtype_sql_time_tz */
|
||||
sizeof(ISC_TIMESTAMP_TZ) /* dtype_timestamp_tz */
|
||||
sizeof(ISC_TIMESTAMP_TZ), /* dtype_timestamp_tz */
|
||||
sizeof(ISC_TIME_TZ_EX), /* dtype_ex_time_tz */
|
||||
sizeof(ISC_TIMESTAMP_TZ_EX) /* dtype_ex_timestamp_tz */
|
||||
};
|
||||
|
||||
|
||||
@ -179,7 +185,9 @@ static const USHORT type_significant_bits[DTYPE_TYPE_MAX] =
|
||||
0, // dtype_dec128
|
||||
0, // dtype_int128
|
||||
0, // dtype_sql_time_tz
|
||||
0 // dtype_timestamp_tz
|
||||
0, // dtype_timestamp_tz
|
||||
0, // dtype_ex_time_tz
|
||||
0 // dtype_ex_timestamp_tz
|
||||
};
|
||||
|
||||
#endif /* JRD_ALIGN_H */
|
||||
|
@ -104,7 +104,9 @@ const BYTE CVT2_compare_priority[] =
|
||||
16, // dec64 - go after dtype_d_float
|
||||
17, // dec128 - go after dec64 and before dtype_sql_date
|
||||
20, // dtype_sql_time_tz - go after dtype_sql_time
|
||||
22 // dtype_timestamp_tz - go after dtype_timestamp
|
||||
22, // dtype_timestamp_tz - go after dtype_timestamp
|
||||
99, // dtype_ex_time_tz - should not be used here
|
||||
99 // dtype_ex_timestamp_tz - should not be used here
|
||||
};
|
||||
|
||||
static inline int QUAD_COMPARE(const SQUAD* arg1, const SQUAD* arg2)
|
||||
@ -236,6 +238,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
return 1;
|
||||
return -1;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_sql_time:
|
||||
if (*(ULONG *) p1 == *(ULONG *) p2)
|
||||
@ -274,6 +277,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
return (arg1->dsc_length > l) ? 1 : (arg2->dsc_length > l) ? -1 : 0;
|
||||
}
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_timestamp:
|
||||
if (((SLONG *) p1)[0] > ((SLONG *) p2)[0])
|
||||
@ -423,6 +427,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
switch (arg1->dsc_dtype)
|
||||
{
|
||||
case dtype_ex_timestamp_tz:
|
||||
case dtype_timestamp_tz:
|
||||
{
|
||||
DSC desc;
|
||||
@ -447,6 +452,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
return CVT2_compare(arg1, &desc, 0);
|
||||
}
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_sql_time_tz:
|
||||
{
|
||||
DSC desc;
|
||||
|
@ -440,6 +440,7 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor
|
||||
value->vlu_misc.vlu_sql_time = *(GDS_TIME*) from.dsc_address;
|
||||
return;
|
||||
|
||||
case dtype_ex_time_tz:
|
||||
case dtype_sql_time_tz:
|
||||
value->vlu_misc.vlu_sql_time_tz = *(ISC_TIME_TZ*) from.dsc_address;
|
||||
return;
|
||||
@ -452,6 +453,7 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor
|
||||
value->vlu_misc.vlu_timestamp = *(GDS_TIMESTAMP*) from.dsc_address;
|
||||
return;
|
||||
|
||||
case dtype_ex_timestamp_tz:
|
||||
case dtype_timestamp_tz:
|
||||
value->vlu_misc.vlu_timestamp_tz = *(ISC_TIMESTAMP_TZ*) from.dsc_address;
|
||||
return;
|
||||
|
@ -373,6 +373,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo
|
||||
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
if (!Firebird::TimeStamp::isValidTime(*(GDS_TIME*) from_desc->dsc_address))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_time_range_exceeded));
|
||||
@ -381,6 +382,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo
|
||||
|
||||
case dtype_timestamp:
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
if (!Firebird::TimeStamp::isValidTimeStamp(*(GDS_TIMESTAMP*) from_desc->dsc_address))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_datetime_range_exceeded));
|
||||
|
@ -374,6 +374,11 @@ USHORT PAR_datatype(BlrReader& blrReader, dsc* desc)
|
||||
desc->dsc_length = sizeof(ISC_TIMESTAMP_TZ);
|
||||
break;
|
||||
|
||||
case blr_ex_timestamp_tz:
|
||||
desc->dsc_dtype = dtype_ex_timestamp_tz;
|
||||
desc->dsc_length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
break;
|
||||
|
||||
case blr_sql_date:
|
||||
desc->dsc_dtype = dtype_sql_date;
|
||||
desc->dsc_length = type_lengths[dtype_sql_date];
|
||||
@ -389,6 +394,11 @@ USHORT PAR_datatype(BlrReader& blrReader, dsc* desc)
|
||||
desc->dsc_length = type_lengths[dtype_sql_time_tz];
|
||||
break;
|
||||
|
||||
case blr_ex_time_tz:
|
||||
desc->dsc_dtype = dtype_ex_time_tz;
|
||||
desc->dsc_length = type_lengths[dtype_ex_time_tz];
|
||||
break;
|
||||
|
||||
case blr_double:
|
||||
case blr_d_float:
|
||||
desc->dsc_dtype = dtype_double;
|
||||
|
@ -163,6 +163,11 @@ void BlrFromMessage::buildBlr(IMessageMetadata* metadata)
|
||||
dtype = dtype_sql_time_tz;
|
||||
break;
|
||||
|
||||
case SQL_TIME_TZ_EX:
|
||||
appendUChar(blr_ex_time_tz);
|
||||
dtype = dtype_ex_time_tz;
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP:
|
||||
appendUChar(blr_timestamp);
|
||||
dtype = dtype_timestamp;
|
||||
@ -173,6 +178,11 @@ void BlrFromMessage::buildBlr(IMessageMetadata* metadata)
|
||||
dtype = dtype_timestamp_tz;
|
||||
break;
|
||||
|
||||
case SQL_TIMESTAMP_TZ_EX:
|
||||
appendUChar(blr_ex_timestamp_tz);
|
||||
dtype = dtype_ex_timestamp_tz;
|
||||
break;
|
||||
|
||||
case SQL_BLOB:
|
||||
if (protocol >= PROTOCOL_VERSION12)
|
||||
{
|
||||
|
@ -178,7 +178,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_text;
|
||||
desc->dsc_length = *blr++;
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_text];
|
||||
break;
|
||||
|
||||
case blr_varying:
|
||||
@ -188,7 +187,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_varying;
|
||||
desc->dsc_length = *blr++ + sizeof(SSHORT);
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_varying];
|
||||
break;
|
||||
|
||||
case blr_cstring:
|
||||
@ -198,7 +196,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_cstring;
|
||||
desc->dsc_length = *blr++;
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_cstring];
|
||||
break;
|
||||
|
||||
// Parse the tagged blr types correctly
|
||||
@ -212,7 +209,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_scale += (*blr++) << 8;
|
||||
desc->dsc_length = *blr++;
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_text];
|
||||
break;
|
||||
|
||||
case blr_varying2:
|
||||
@ -224,7 +220,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_scale += (*blr++) << 8;
|
||||
desc->dsc_length = *blr++ + sizeof(SSHORT);
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_varying];
|
||||
break;
|
||||
|
||||
case blr_cstring2:
|
||||
@ -236,7 +231,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_scale += (*blr++) << 8;
|
||||
desc->dsc_length = *blr++;
|
||||
desc->dsc_length += (*blr++) << 8;
|
||||
align = type_alignments[dtype_cstring];
|
||||
break;
|
||||
|
||||
case blr_short:
|
||||
@ -245,7 +239,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_short;
|
||||
desc->dsc_length = sizeof(SSHORT);
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_short];
|
||||
break;
|
||||
|
||||
case blr_long:
|
||||
@ -254,7 +247,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_long];
|
||||
break;
|
||||
|
||||
case blr_int64:
|
||||
@ -263,7 +255,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_int64;
|
||||
desc->dsc_length = sizeof(SINT64);
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_int64];
|
||||
break;
|
||||
|
||||
case blr_quad:
|
||||
@ -272,39 +263,33 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
desc->dsc_dtype = dtype_quad;
|
||||
desc->dsc_length = sizeof(SLONG) * 2;
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_quad];
|
||||
break;
|
||||
|
||||
case blr_float:
|
||||
desc->dsc_dtype = dtype_real;
|
||||
desc->dsc_length = sizeof(float);
|
||||
align = type_alignments[dtype_real];
|
||||
break;
|
||||
|
||||
case blr_double:
|
||||
case blr_d_float:
|
||||
desc->dsc_dtype = dtype_double;
|
||||
desc->dsc_length = sizeof(double);
|
||||
align = type_alignments[dtype_double];
|
||||
break;
|
||||
|
||||
case blr_dec64:
|
||||
desc->dsc_dtype = dtype_dec64;
|
||||
desc->dsc_length = sizeof(Decimal64);
|
||||
align = type_alignments[dtype_dec64];
|
||||
break;
|
||||
|
||||
case blr_dec128:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
align = type_alignments[dtype_dec128];
|
||||
break;
|
||||
|
||||
case blr_int128:
|
||||
desc->dsc_dtype = dtype_int128;
|
||||
desc->dsc_length = sizeof(Int128);
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_int128];
|
||||
break;
|
||||
|
||||
// this case cannot occur as switch paramater is char and blr_blob
|
||||
@ -313,7 +298,6 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
//case blr_blob:
|
||||
// desc->dsc_dtype = dtype_blob;
|
||||
// desc->dsc_length = sizeof (SLONG) * 2;
|
||||
// align = type_alignments [dtype_blob];
|
||||
// break;
|
||||
|
||||
case blr_blob2:
|
||||
@ -329,51 +313,54 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
USHORT textType = *blr++;
|
||||
textType += (*blr++) << 8;
|
||||
desc->setTextType(textType);
|
||||
|
||||
align = type_alignments[dtype_blob];
|
||||
}
|
||||
break;
|
||||
|
||||
case blr_timestamp:
|
||||
desc->dsc_dtype = dtype_timestamp;
|
||||
desc->dsc_length = sizeof(SLONG) * 2;
|
||||
align = type_alignments[dtype_timestamp];
|
||||
break;
|
||||
|
||||
case blr_timestamp_tz:
|
||||
desc->dsc_dtype = dtype_timestamp_tz;
|
||||
desc->dsc_length = sizeof(ISC_TIMESTAMP_TZ);
|
||||
align = type_alignments[dtype_timestamp_tz];
|
||||
break;
|
||||
|
||||
case blr_ex_timestamp_tz:
|
||||
desc->dsc_dtype = dtype_ex_timestamp_tz;
|
||||
desc->dsc_length = sizeof(ISC_TIMESTAMP_TZ_EX);
|
||||
break;
|
||||
|
||||
case blr_sql_date:
|
||||
desc->dsc_dtype = dtype_sql_date;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
align = type_alignments[dtype_sql_date];
|
||||
break;
|
||||
|
||||
case blr_sql_time:
|
||||
desc->dsc_dtype = dtype_sql_time;
|
||||
desc->dsc_length = sizeof(ULONG);
|
||||
align = type_alignments[dtype_sql_time];
|
||||
break;
|
||||
|
||||
case blr_sql_time_tz:
|
||||
desc->dsc_dtype = dtype_sql_time_tz;
|
||||
desc->dsc_length = sizeof(ISC_TIME_TZ);
|
||||
align = type_alignments[dtype_sql_time_tz];
|
||||
break;
|
||||
|
||||
case blr_ex_time_tz:
|
||||
desc->dsc_dtype = dtype_ex_time_tz;
|
||||
desc->dsc_length = sizeof(ISC_TIME_TZ_EX);
|
||||
break;
|
||||
|
||||
case blr_bool:
|
||||
desc->dsc_dtype = dtype_boolean;
|
||||
desc->dsc_length = sizeof(UCHAR);
|
||||
align = type_alignments[dtype_boolean];
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
align = type_alignments[desc->dsc_dtype];
|
||||
|
||||
if (desc->dsc_dtype == dtype_varying)
|
||||
net_length += 4 + ((desc->dsc_length - 2 + 3) & ~3);
|
||||
|
@ -687,6 +687,12 @@ public:
|
||||
unsigned year, unsigned month, unsigned day,
|
||||
unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone);
|
||||
Firebird::IInt128* getInt128(Firebird::CheckStatusWrapper* status);
|
||||
void decodeTimeTzEx(Firebird::CheckStatusWrapper* status, const ISC_TIME_TZ_EX* timeEx,
|
||||
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
|
||||
unsigned timeZoneBufferLength, char* timeZoneBuffer);
|
||||
void decodeTimeStampTzEx(Firebird::CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ_EX* timeStampEx,
|
||||
unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds,
|
||||
unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer);
|
||||
};
|
||||
|
||||
} // namespace Why
|
||||
|
@ -666,7 +666,7 @@ void UtilInterface::decodeTime(ISC_TIME time,
|
||||
*fractions = time % ISC_TIME_SECONDS_PRECISION;
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ* timeTz,
|
||||
void decodeTimeTzWithFallback(CheckStatusWrapper* status, const ISC_TIME_TZ* timeTz, SLONG gmtFallback,
|
||||
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
|
||||
unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
@ -674,7 +674,7 @@ void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ*
|
||||
{
|
||||
tm times;
|
||||
int intFractions;
|
||||
bool tzLookup = TimeZoneUtil::decodeTime(*timeTz, timeZoneBuffer != nullptr, CVT_commonCallbacks,
|
||||
bool tzLookup = TimeZoneUtil::decodeTime(*timeTz, true, gmtFallback, CVT_commonCallbacks,
|
||||
×, &intFractions);
|
||||
|
||||
if (hours)
|
||||
@ -690,12 +690,7 @@ void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ*
|
||||
*fractions = (unsigned) intFractions;
|
||||
|
||||
if (timeZoneBuffer)
|
||||
{
|
||||
if (tzLookup)
|
||||
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeTz->time_zone);
|
||||
else
|
||||
strncpy(timeZoneBuffer, TimeZoneUtil::GMT_FALLBACK, timeZoneBufferLength);
|
||||
}
|
||||
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeTz->time_zone, !tzLookup, gmtFallback);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -703,6 +698,23 @@ void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ*
|
||||
}
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeTz(CheckStatusWrapper* status, const ISC_TIME_TZ* timeTz,
|
||||
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
|
||||
unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
decodeTimeTzWithFallback(status, timeTz, TimeZoneUtil::NO_OFFSET,
|
||||
hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeTzEx(Firebird::CheckStatusWrapper* status, const ISC_TIME_TZ_EX* timeEx,
|
||||
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
|
||||
unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
decodeTimeTzWithFallback(status, reinterpret_cast<const ISC_TIME_TZ*>(timeEx),
|
||||
timeZoneBuffer ? timeEx->ext_offset : TimeZoneUtil::NO_OFFSET,
|
||||
hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
|
||||
void UtilInterface::encodeTimeTz(CheckStatusWrapper* status, ISC_TIME_TZ* timeTz,
|
||||
unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone)
|
||||
{
|
||||
@ -718,7 +730,7 @@ void UtilInterface::encodeTimeTz(CheckStatusWrapper* status, ISC_TIME_TZ* timeTz
|
||||
}
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ* timeStampTz,
|
||||
void decodeTimeStampWithFallback(CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ* timeStampTz, SLONG gmtFallback,
|
||||
unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds,
|
||||
unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
@ -726,7 +738,7 @@ void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIME
|
||||
{
|
||||
tm times;
|
||||
int intFractions;
|
||||
bool tzLookup = TimeZoneUtil::decodeTimeStamp(*timeStampTz, timeZoneBuffer != nullptr, ×, &intFractions);
|
||||
bool tzLookup = TimeZoneUtil::decodeTimeStamp(*timeStampTz, true, gmtFallback, ×, &intFractions);
|
||||
|
||||
if (year)
|
||||
*year = times.tm_year + 1900;
|
||||
@ -750,12 +762,7 @@ void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIME
|
||||
*fractions = (unsigned) intFractions;
|
||||
|
||||
if (timeZoneBuffer)
|
||||
{
|
||||
if (tzLookup)
|
||||
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeStampTz->time_zone);
|
||||
else
|
||||
strncpy(timeZoneBuffer, TimeZoneUtil::GMT_FALLBACK, timeZoneBufferLength);
|
||||
}
|
||||
TimeZoneUtil::format(timeZoneBuffer, timeZoneBufferLength, timeStampTz->time_zone, !tzLookup, gmtFallback);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -763,6 +770,23 @@ void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIME
|
||||
}
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeStampTz(CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ* timeStampTz,
|
||||
unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds,
|
||||
unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
decodeTimeStampWithFallback(status, timeStampTz, TimeZoneUtil::NO_OFFSET,
|
||||
year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
|
||||
void UtilInterface::decodeTimeStampTzEx(CheckStatusWrapper* status, const ISC_TIMESTAMP_TZ_EX* timeStampEx,
|
||||
unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds,
|
||||
unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer)
|
||||
{
|
||||
decodeTimeStampWithFallback(status, reinterpret_cast<const ISC_TIMESTAMP_TZ*>(timeStampEx),
|
||||
timeZoneBuffer ? timeStampEx->ext_offset : TimeZoneUtil::NO_OFFSET,
|
||||
year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer);
|
||||
}
|
||||
|
||||
void UtilInterface::encodeTimeStampTz(CheckStatusWrapper* status, ISC_TIMESTAMP_TZ* timeStampTz,
|
||||
unsigned year, unsigned month, unsigned day, unsigned hours, unsigned minutes, unsigned seconds,
|
||||
unsigned fractions, const char* timeZone)
|
||||
|
Loading…
Reference in New Issue
Block a user