From a02f0dea8163de64caa13c9a8637fa28eea0e9d3 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Mon, 3 May 2021 11:02:54 -0300 Subject: [PATCH] Improvement #6788 - Extend EXTRACT to extract time zone strings. --- doc/sql.extensions/README.keywords | 1 + doc/sql.extensions/README.time_zone.md | 4 ++ src/common/keywords.cpp | 1 + src/dsql/ExprNodes.cpp | 63 ++++++++++++++++++-------- src/dsql/parse.y | 2 + src/include/firebird/impl/blr.h | 1 + 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/doc/sql.extensions/README.keywords b/doc/sql.extensions/README.keywords index 6dae3f5b21..5b01114145 100644 --- a/doc/sql.extensions/README.keywords +++ b/doc/sql.extensions/README.keywords @@ -372,6 +372,7 @@ Firebird 4.0 SQL (1) SYSTEM (1) TIES + TIMEZONE_NAME * TOTALORDER * TRAPS * ZONE diff --git a/doc/sql.extensions/README.time_zone.md b/doc/sql.extensions/README.time_zone.md index 5480cb1536..28d248bea4 100644 --- a/doc/sql.extensions/README.time_zone.md +++ b/doc/sql.extensions/README.time_zone.md @@ -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 diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index 0639bc6703..cc6f1ed539 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -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}, diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index b94284fccd..267c75a0c2 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -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(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; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 34020f2cd3..af94ac45d4 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -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 diff --git a/src/include/firebird/impl/blr.h b/src/include/firebird/impl/blr.h index 7d8c1747e1..031c27be1d 100644 --- a/src/include/firebird/impl/blr.h +++ b/src/include/firebird/impl/blr.h @@ -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