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

Improvement #6788 - Extend EXTRACT to extract time zone strings.

This commit is contained in:
Adriano dos Santos Fernandes 2021-05-03 11:02:54 -03:00
parent 8429c95795
commit a02f0dea81
6 changed files with 54 additions and 18 deletions

View File

@ -372,6 +372,7 @@ Firebird 4.0
SQL (1)
SYSTEM (1)
TIES
TIMEZONE_NAME *
TOTALORDER *
TRAPS *
ZONE

View File

@ -296,6 +296,7 @@ select timestamp '2018-01-01 12:00 GMT' at local
Two new `EXTRACT` expressions has been added:
- `TIMEZONE_HOUR`: extracts the time zone hours displacement
- `TIMEZONE_MINUTE`: extracts the time zone minutes displacement
- `TIMEZONE_NAME`: extracts the time zone region or displacement string
#### Examples
@ -305,6 +306,9 @@ select extract(timezone_hour from current_time)
select extract(timezone_minute from current_timestamp)
from rdb$database;
select extract(timezone_name from current_timestamp)
from rdb$database;
```
### `LOCALTIME` expression

View File

@ -492,6 +492,7 @@ static const TOK tokens[] =
{TOK_TIMEOUT, "TIMEOUT", true},
{TOK_TIMEZONE_HOUR, "TIMEZONE_HOUR", false},
{TOK_TIMEZONE_MINUTE, "TIMEZONE_MINUTE", false},
{TOK_TIMEZONE_NAME, "TIMEZONE_NAME", true},
{TOK_TO, "TO", false},
{TOK_TOTALORDER, "TOTALORDER", true},
{TOK_TRAILING, "TRAILING", false},

View File

@ -5334,6 +5334,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
if (!nodeIs<NullNode>(sub1) &&
!sub1->getDsqlDesc().isTime() &&
!sub1->getDsqlDesc().isTimeStamp())
@ -5385,6 +5386,10 @@ void ExtractNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
break;
case blr_extract_timezone_name:
desc->makeVarying(TimeZoneUtil::MAX_LEN, ttype_ascii);
break;
default:
desc->makeShort(0);
break;
@ -5406,6 +5411,10 @@ void ExtractNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* de
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
break;
case blr_extract_timezone_name:
desc->makeVarying(TimeZoneUtil::MAX_LEN, ttype_ascii);
break;
default:
desc->makeShort(0);
break;
@ -5484,6 +5493,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
{
ISC_TIME_TZ timeTz = TimeZoneUtil::timeToTimeTz(
*(ISC_TIME*) value->dsc_address, &EngineCallbacks::instance);
@ -5512,6 +5522,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
timeStampTz.utc_timestamp.timestamp_date = TimeZoneUtil::TIME_TZ_BASE_DATE;
timeStampTz.utc_timestamp.timestamp_time = ((ISC_TIME_TZ*) value->dsc_address)->utc_time;
timeStampTz.time_zone = ((ISC_TIME_TZ*) value->dsc_address)->time_zone;
@ -5532,6 +5543,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_extract_millisecond:
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_date));
break;
@ -5546,6 +5558,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
{
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
{
dsc tempDsc;
tempDsc.makeTimestampTz(&timeStampTz);
@ -5563,6 +5576,7 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
{
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
case blr_extract_timezone_name:
timeStampTz = *(ISC_TIMESTAMP_TZ*) value->dsc_address;
break;
@ -5578,28 +5592,41 @@ dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
break;
}
if (blrSubOp == blr_extract_timezone_hour || blrSubOp == blr_extract_timezone_minute)
{
int tzSign;
unsigned tzh, tzm;
TimeZoneUtil::extractOffset(timeStampTz, &tzSign, &tzh, &tzm);
switch (blrSubOp)
{
case blr_extract_timezone_hour:
*(SSHORT*) impure->vlu_desc.dsc_address = tzSign * int(tzh);
return &impure->vlu_desc;
case blr_extract_timezone_minute:
*(SSHORT*) impure->vlu_desc.dsc_address = tzSign * int(tzm);
return &impure->vlu_desc;
}
}
USHORT part;
switch (blrSubOp)
{
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
{
int tzSign;
unsigned tzh, tzm;
TimeZoneUtil::extractOffset(timeStampTz, &tzSign, &tzh, &tzm);
switch (blrSubOp)
{
case blr_extract_timezone_hour:
*(SSHORT*) impure->vlu_desc.dsc_address = tzSign * int(tzh);
return &impure->vlu_desc;
case blr_extract_timezone_minute:
*(SSHORT*) impure->vlu_desc.dsc_address = tzSign * int(tzm);
return &impure->vlu_desc;
}
break;
}
case blr_extract_timezone_name:
{
char timeZoneBuffer[TimeZoneUtil::MAX_SIZE];
const auto len = TimeZoneUtil::format(timeZoneBuffer, sizeof(timeZoneBuffer), timeStampTz.time_zone);
impure->vlu_desc.makeText(len, ttype_ascii, (UCHAR*) timeZoneBuffer);
EVL_make_value(tdbb, &impure->vlu_desc, impure);
return &impure->vlu_desc;
}
case blr_extract_year:
part = times.tm_year + 1900;
break;

View File

@ -8579,6 +8579,7 @@ timestamp_part
| MILLISECOND { $$ = blr_extract_millisecond; }
| TIMEZONE_HOUR { $$ = blr_extract_timezone_hour; }
| TIMEZONE_MINUTE { $$ = blr_extract_timezone_minute; }
| TIMEZONE_NAME { $$ = blr_extract_timezone_name; }
| WEEK { $$ = blr_extract_week; }
| WEEKDAY { $$ = blr_extract_weekday; }
| YEARDAY { $$ = blr_extract_yearday; }
@ -9037,6 +9038,7 @@ non_reserved_word
| SQL
| SYSTEM
| TIES
| TIMEZONE_NAME
| TOTALORDER
| TRAPS
| ZONE

View File

@ -288,6 +288,7 @@
#define blr_extract_week (unsigned char)9
#define blr_extract_timezone_hour (unsigned char)10
#define blr_extract_timezone_minute (unsigned char)11
#define blr_extract_timezone_name (unsigned char)12
#define blr_current_date (unsigned char)160
#define blr_current_timestamp (unsigned char)161