mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
* Refactoring of CAST FORMAT Move CAST FORMAT logic to separate file. Separation of logic into parsing stage and execution stage. Add more FORMAT validation based on SQL standard. * Add more unit tests for incorrect FORMAT * Remove incorrect const specifier * Fixes after review Minor code changes. Move public CVT_FORMAT functions to CvtFormat.h. Add new error message if same is used pattern twice in string to datetime conversion. * Fix indents in comments * Add new files to windows build * Remove constexpr specifier from functions that is not real constexpr Because std::isdigit and std::isalpha are not constexpr. --------- Co-authored-by: Artyom Ivanov <artyom.ivanov@red-soft.ru>
This commit is contained in:
parent
f2d12e403b
commit
174038cbf5
@ -62,6 +62,7 @@
|
||||
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\cvt.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\CvtFormat.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\db_alias.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\DecFloat.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\dllinst.cpp" />
|
||||
@ -170,6 +171,8 @@
|
||||
<ClInclude Include="..\..\..\src\common\config\dir_list.h" />
|
||||
<ClInclude Include="..\..\..\src\common\CsConvert.h" />
|
||||
<ClInclude Include="..\..\..\src\common\cvt.h" />
|
||||
<ClInclude Include="..\..\..\src\common\CvtFormat.h" />
|
||||
<ClInclude Include="..\..\..\src\common\CvtFormatImpl.h" />
|
||||
<ClInclude Include="..\..\..\src\common\db_alias.h" />
|
||||
<ClInclude Include="..\..\..\src\common\DecFloat.h" />
|
||||
<ClInclude Include="..\..\..\src\common\dllinst.h" />
|
||||
|
@ -30,6 +30,9 @@
|
||||
<ClCompile Include="..\..\..\src\common\cvt.cpp">
|
||||
<Filter>common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\CvtFormat.cpp">
|
||||
<Filter>common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\db_alias.cpp">
|
||||
<Filter>common</Filter>
|
||||
</ClCompile>
|
||||
@ -275,6 +278,12 @@
|
||||
<ClInclude Include="..\..\..\src\common\cvt.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\CvtFormat.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\CvtFormatImpl.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\db_alias.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
|
1693
src/common/CvtFormat.cpp
Normal file
1693
src/common/CvtFormat.cpp
Normal file
File diff suppressed because it is too large
Load Diff
11
src/common/CvtFormat.h
Normal file
11
src/common/CvtFormat.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef COMMON_CVT_FORMAT_H
|
||||
#define COMMON_CVT_FORMAT_H
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../common/cvt.h"
|
||||
|
||||
Firebird::string CVT_format_datetime_to_string(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb);
|
||||
ISC_TIMESTAMP_TZ CVT_format_string_to_datetime(const dsc* desc, const Firebird::string& format,
|
||||
const Firebird::EXPECT_DATETIME expectedType, Firebird::Callbacks* cb);
|
||||
|
||||
#endif // COMMON_CVT_FORMAT_H
|
42
src/common/CvtFormatImpl.h
Normal file
42
src/common/CvtFormatImpl.h
Normal file
@ -0,0 +1,42 @@
|
||||
CVT_FORMAT(__LINE__, YEAR)
|
||||
CVT_FORMAT(__LINE__, YYYY)
|
||||
CVT_FORMAT(__LINE__, YYY)
|
||||
CVT_FORMAT(__LINE__, YY)
|
||||
CVT_FORMAT(__LINE__, Y)
|
||||
CVT_FORMAT(__LINE__, RR)
|
||||
CVT_FORMAT(__LINE__, RRRR)
|
||||
CVT_FORMAT(__LINE__, Q)
|
||||
CVT_FORMAT(__LINE__, MM)
|
||||
CVT_FORMAT(__LINE__, MON)
|
||||
CVT_FORMAT(__LINE__, MONTH)
|
||||
CVT_FORMAT(__LINE__, RM)
|
||||
CVT_FORMAT(__LINE__, WW)
|
||||
CVT_FORMAT(__LINE__, W)
|
||||
CVT_FORMAT(__LINE__, D)
|
||||
CVT_FORMAT(__LINE__, DAY)
|
||||
CVT_FORMAT(__LINE__, DD)
|
||||
CVT_FORMAT(__LINE__, DDD)
|
||||
CVT_FORMAT(__LINE__, DY)
|
||||
CVT_FORMAT(__LINE__, J)
|
||||
CVT_FORMAT(__LINE__, HH)
|
||||
CVT_FORMAT(__LINE__, HH12)
|
||||
CVT_FORMAT(__LINE__, HH24)
|
||||
CVT_FORMAT(__LINE__, MI)
|
||||
CVT_FORMAT(__LINE__, SS)
|
||||
CVT_FORMAT(__LINE__, SSSSS)
|
||||
CVT_FORMAT(__LINE__, FF1)
|
||||
CVT_FORMAT(__LINE__, FF2)
|
||||
CVT_FORMAT(__LINE__, FF3)
|
||||
CVT_FORMAT(__LINE__, FF4)
|
||||
CVT_FORMAT(__LINE__, FF5)
|
||||
CVT_FORMAT(__LINE__, FF6)
|
||||
CVT_FORMAT(__LINE__, FF7)
|
||||
CVT_FORMAT(__LINE__, FF8)
|
||||
CVT_FORMAT(__LINE__, FF9)
|
||||
CVT_FORMAT(__LINE__, TZH)
|
||||
CVT_FORMAT(__LINE__, TZM)
|
||||
CVT_FORMAT(__LINE__, TZR)
|
||||
CVT_FORMAT2(__LINE__, A.M., AM)
|
||||
CVT_FORMAT2(__LINE__, P.M., PM)
|
||||
CVT_FORMAT_FLAG(__LINE__, SEPARATOR)
|
||||
|
1382
src/common/cvt.cpp
1382
src/common/cvt.cpp
File diff suppressed because it is too large
Load Diff
@ -105,8 +105,5 @@ SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird::EXPECT_DATETIME,
|
||||
bool, Firebird::Callbacks*);
|
||||
const UCHAR* CVT_get_bytes(const dsc*, unsigned&);
|
||||
Firebird::string CVT_datetime_to_format_string(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb);
|
||||
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format,
|
||||
const Firebird::EXPECT_DATETIME expectedType, Firebird::Callbacks* cb);
|
||||
|
||||
#endif //COMMON_CVT_H
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "boost/test/unit_test.hpp"
|
||||
#include "../common/tests/CvtTestUtils.h"
|
||||
#include "../jrd/cvt_proto.h"
|
||||
|
||||
#include "../common/StatusArg.h"
|
||||
#include "../common/CvtFormat.h"
|
||||
|
||||
using namespace Firebird;
|
||||
using namespace Jrd;
|
||||
@ -33,7 +35,7 @@ static void testCVTDatetimeToFormatString(T date, const string& format, const st
|
||||
|
||||
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
|
||||
|
||||
string result = CVT_datetime_to_format_string(&desc, format, &cb);
|
||||
string result = CVT_format_datetime_to_string(&desc, format, &cb);
|
||||
|
||||
BOOST_TEST(result == expected, "\nRESULT: " << result.c_str() << "\nEXPECTED: " << expected.c_str());
|
||||
}
|
||||
@ -278,7 +280,7 @@ static void testCVTStringToFormatDateTime(const string& date, const string& form
|
||||
BOOST_TEST_INFO("INPUT: " << "\"" << date.c_str() << "\"");
|
||||
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
|
||||
|
||||
const ISC_TIMESTAMP_TZ result = CVT_string_to_format_datetime(&desc, format, expectedType, &cb);
|
||||
const ISC_TIMESTAMP_TZ result = CVT_format_string_to_datetime(&desc, format, expectedType, &cb);
|
||||
|
||||
struct tm resultTimes;
|
||||
memset(&resultTimes, 0, sizeof(resultTimes));
|
||||
@ -340,7 +342,7 @@ static void testExceptionCvtStringToFormatDateTime(const string& date, const str
|
||||
BOOST_TEST_INFO("INPUT: " << "\"" << date.c_str() << "\"");
|
||||
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
|
||||
|
||||
BOOST_CHECK_THROW(CVT_string_to_format_datetime(&desc, format, expect_timestamp_tz, &cb), status_exception);
|
||||
BOOST_CHECK_THROW(CVT_format_string_to_datetime(&desc, format, expect_timestamp_tz, &cb), status_exception);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(FunctionalTest)
|
||||
@ -590,9 +592,16 @@ BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_EXCEPTION_CHECK)
|
||||
testExceptionCvtStringToFormatDateTime("2000.12.11", "WRONG FORMAT", cb);
|
||||
testExceptionCvtStringToFormatDateTime("2000.12.11", "YYYY.MM.DD SS", cb);
|
||||
testExceptionCvtStringToFormatDateTime("2000.12", "YYYY.MM.DD", cb);
|
||||
testExceptionCvtStringToFormatDateTime("2000.12", "YYYY", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.P.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("2 20 200 2000 2000", "Y YY YYY YYYY YEAR", cb);
|
||||
testExceptionCvtStringToFormatDateTime("20 2000", "RR RRRR", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("2000 2000", "YYYY RRRR", cb);
|
||||
testExceptionCvtStringToFormatDateTime("2000 20", "YYYY RR", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("200 2", "DDD MM", cb);
|
||||
testExceptionCvtStringToFormatDateTime("200 2", "DDD DD", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("24 12 A.M.", "HH24 HH12 P.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("24 12", "HH24 HH12", cb);
|
||||
@ -600,6 +609,10 @@ BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_EXCEPTION_CHECK)
|
||||
testExceptionCvtStringToFormatDateTime("12", "HH12", cb);
|
||||
testExceptionCvtStringToFormatDateTime("A.M.", "P.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("P.M.", "A.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("10 P.M. A.M.", "HH P.M. A.M.", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.P.", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH12 A.M.", cb);
|
||||
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH12 P.M.", cb);
|
||||
@ -611,6 +624,8 @@ BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_EXCEPTION_CHECK)
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("30 1", "TZM SS", cb);
|
||||
testExceptionCvtStringToFormatDateTime("30", "TZM", cb);
|
||||
|
||||
testExceptionCvtStringToFormatDateTime("12 12", "HH24 HH24", cb);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // FunctionalTest
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../common/TimeZoneUtil.h"
|
||||
#include "../common/classes/FpeControl.h"
|
||||
#include "../common/classes/VaryStr.h"
|
||||
#include "../common/CvtFormat.h"
|
||||
#include "../dsql/ExprNodes.h"
|
||||
#include "../dsql/BoolNodes.h"
|
||||
#include "../dsql/StmtNodes.h"
|
||||
@ -3789,7 +3790,7 @@ dsc* CastNode::perform(thread_db* tdbb, impure_value* impure, dsc* value,
|
||||
{
|
||||
if (DTYPE_IS_TEXT(impure->vlu_desc.dsc_dtype))
|
||||
{
|
||||
string result = CVT_datetime_to_format_string(value, format, &EngineCallbacks::instance);
|
||||
string result = CVT_format_datetime_to_string(value, format, &EngineCallbacks::instance);
|
||||
USHORT dscLength = DSC_string_length(&impure->vlu_desc);
|
||||
string::size_type resultLength = result.length();
|
||||
if (resultLength > dscLength)
|
||||
@ -3815,21 +3816,21 @@ dsc* CastNode::perform(thread_db* tdbb, impure_value* impure, dsc* value,
|
||||
{
|
||||
case dtype_sql_time:
|
||||
{
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_time,
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_format_string_to_datetime(value, format, expect_sql_time,
|
||||
&EngineCallbacks::instance);
|
||||
*(ISC_TIME*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp.timestamp_time;
|
||||
break;
|
||||
}
|
||||
case dtype_sql_date:
|
||||
{
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_date,
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_format_string_to_datetime(value, format, expect_sql_date,
|
||||
&EngineCallbacks::instance);
|
||||
*(ISC_DATE*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp.timestamp_date;
|
||||
break;
|
||||
}
|
||||
case dtype_timestamp:
|
||||
{
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_timestamp,
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_format_string_to_datetime(value, format, expect_timestamp,
|
||||
&EngineCallbacks::instance);
|
||||
*(ISC_TIMESTAMP*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp;
|
||||
break;
|
||||
@ -3837,7 +3838,7 @@ dsc* CastNode::perform(thread_db* tdbb, impure_value* impure, dsc* value,
|
||||
case dtype_sql_time_tz:
|
||||
case dtype_ex_time_tz:
|
||||
{
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_time_tz,
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_format_string_to_datetime(value, format, expect_sql_time_tz,
|
||||
&EngineCallbacks::instance);
|
||||
*(ISC_TIME_TZ*) impure->vlu_desc.dsc_address = TimeZoneUtil::timeStampTzToTimeTz(timestampTZ);
|
||||
break;
|
||||
@ -3845,7 +3846,7 @@ dsc* CastNode::perform(thread_db* tdbb, impure_value* impure, dsc* value,
|
||||
case dtype_timestamp_tz:
|
||||
case dtype_ex_timestamp_tz:
|
||||
{
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_timestamp_tz,
|
||||
ISC_TIMESTAMP_TZ timestampTZ = CVT_format_string_to_datetime(value, format, expect_timestamp_tz,
|
||||
&EngineCallbacks::instance);
|
||||
*(ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address = timestampTZ;
|
||||
break;
|
||||
|
@ -984,3 +984,5 @@ FB_IMPL_MSG(JRD, 981, trailing_part_of_string, -901, "HY", "000", "There is a tr
|
||||
FB_IMPL_MSG(JRD, 982, pattern_cant_be_used_without_other_pattern, -901, "HY", "000", "@1 can't be used without @2")
|
||||
FB_IMPL_MSG(JRD, 983, pattern_cant_be_used_without_other_pattern_and_vice_versa, -901, "HY", "000", "@1 can't be used without @2 and vice versa")
|
||||
FB_IMPL_MSG(JRD, 984, incompatible_format_patterns, -901, "HY", "000", "@1 incompatible with @2")
|
||||
FB_IMPL_MSG(JRD, 985, only_one_pattern_can_be_used, -901, "HY", "000", "Can use only one of these patterns @1")
|
||||
FB_IMPL_MSG(JRD, 986, can_not_use_same_pattern_twice, -901, "HY", "000", "Cannot use the same pattern twice: @1")
|
||||
|
@ -5727,6 +5727,8 @@ const
|
||||
isc_pattern_cant_be_used_without_other_pattern = 335545302;
|
||||
isc_pattern_cant_be_used_without_other_pattern_and_vice_versa = 335545303;
|
||||
isc_incompatible_format_patterns = 335545304;
|
||||
isc_only_one_pattern_can_be_used = 335545305;
|
||||
isc_can_not_use_same_pattern_twice = 335545306;
|
||||
isc_gfix_db_name = 335740929;
|
||||
isc_gfix_invalid_sw = 335740930;
|
||||
isc_gfix_incmp_sw = 335740932;
|
||||
|
Loading…
Reference in New Issue
Block a user