Fix DateTime64 parsing after constant folding

This commit is contained in:
vdimir 2024-08-06 14:33:28 +00:00
parent 681eafef79
commit 5c4f2c1985
No known key found for this signature in database
GPG Key ID: 6EE4CE2BEDC51862
3 changed files with 29 additions and 1 deletions

View File

@ -5,6 +5,7 @@
#include <Common/assert_cast.h> #include <Common/assert_cast.h>
#include <Common/FieldVisitorToString.h> #include <Common/FieldVisitorToString.h>
#include <Common/SipHash.h> #include <Common/SipHash.h>
#include <DataTypes/DataTypeDateTime64.h>
#include <IO/WriteBuffer.h> #include <IO/WriteBuffer.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
@ -162,6 +163,7 @@ QueryTreeNodePtr ConstantNode::cloneImpl() const
ASTPtr ConstantNode::toASTImpl(const ConvertToASTOptions & options) const ASTPtr ConstantNode::toASTImpl(const ConvertToASTOptions & options) const
{ {
const auto & constant_value_literal = constant_value->getValue(); const auto & constant_value_literal = constant_value->getValue();
const auto & constant_value_type = constant_value->getType();
auto constant_value_ast = std::make_shared<ASTLiteral>(constant_value_literal); auto constant_value_ast = std::make_shared<ASTLiteral>(constant_value_literal);
if (!options.add_cast_for_constants) if (!options.add_cast_for_constants)
@ -169,7 +171,25 @@ ASTPtr ConstantNode::toASTImpl(const ConvertToASTOptions & options) const
if (requiresCastCall()) if (requiresCastCall())
{ {
auto constant_type_name_ast = std::make_shared<ASTLiteral>(constant_value->getType()->getName()); /** Value for DateTime64 is Decimal64, which is serialized as a string literal.
* If we serialize it as is, DateTime64 would be parsed from that string literal, which can be incorrect.
* For example, DateTime64 cannot be parsed from the short value, like '1', while it's a valid Decimal64 value.
* It could also lead to ambiguous parsing because we don't know if the string literal represents a date or a Decimal64 literal.
* For this reason, we use a string literal representing a date instead of a Decimal64 literal.
*/
if (WhichDataType(constant_value_type->getTypeId()).isDateTime64())
{
const auto * date_time_type = typeid_cast<const DataTypeDateTime64 *>(constant_value_type.get());
DecimalField<Decimal64> decimal_value;
if (constant_value_literal.tryGet<DecimalField<Decimal64>>(decimal_value))
{
WriteBufferFromOwnString ostr;
writeDateTimeText(decimal_value.getValue(), date_time_type->getScale(), ostr, date_time_type->getTimeZone());
constant_value_ast = std::make_shared<ASTLiteral>(ostr.str());
}
}
auto constant_type_name_ast = std::make_shared<ASTLiteral>(constant_value_type->getName());
return makeASTFunction("_CAST", std::move(constant_value_ast), std::move(constant_type_name_ast)); return makeASTFunction("_CAST", std::move(constant_value_ast), std::move(constant_type_name_ast));
} }

View File

@ -0,0 +1,2 @@
1970-01-01 00:00:01.000
1970-01-01 00:00:01.000

View File

@ -0,0 +1,6 @@
SET session_timezone = 'UTC';
SELECT toDateTime64('1970-01-01 00:00:01', 3)
FROM remote('127.0.0.{1,2}', system, one)
;