mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Merge pull request #11875 from ClickHouse/fix-fpe-datetime64
Fix strange and wrong code around DateTime64
This commit is contained in:
commit
c2fba5179b
@ -1477,7 +1477,8 @@ private:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out_logs_buf = std::make_unique<WriteBufferFromFile>(server_logs_file, DBMS_DEFAULT_BUFFER_SIZE, O_WRONLY | O_APPEND | O_CREAT);
|
out_logs_buf = std::make_unique<WriteBufferFromFile>(
|
||||||
|
server_logs_file, DBMS_DEFAULT_BUFFER_SIZE, O_WRONLY | O_APPEND | O_CREAT);
|
||||||
wb = out_logs_buf.get();
|
wb = out_logs_buf.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ inline NO_SANITIZE_UNDEFINED uint64_t intExp2(int x)
|
|||||||
return 1ULL << x;
|
return 1ULL << x;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t intExp10(int x)
|
constexpr inline uint64_t intExp10(int x)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (x > 19)
|
if (x > 19)
|
||||||
return std::numeric_limits<uint64_t>::max();
|
return std::numeric_limits<uint64_t>::max();
|
||||||
|
|
||||||
static const uint64_t table[20] =
|
constexpr uint64_t table[20] =
|
||||||
{
|
{
|
||||||
1ULL, 10ULL, 100ULL,
|
1ULL, 10ULL, 100ULL,
|
||||||
1000ULL, 10000ULL, 100000ULL,
|
1000ULL, 10000ULL, 100000ULL,
|
||||||
@ -44,9 +44,10 @@ inline uint64_t intExp10(int x)
|
|||||||
namespace common
|
namespace common
|
||||||
{
|
{
|
||||||
|
|
||||||
inline int exp10_i32(int x)
|
constexpr inline int exp10_i32(int x)
|
||||||
|
{
|
||||||
|
constexpr int values[] =
|
||||||
{
|
{
|
||||||
static const int values[] = {
|
|
||||||
1,
|
1,
|
||||||
10,
|
10,
|
||||||
100,
|
100,
|
||||||
@ -61,74 +62,76 @@ inline int exp10_i32(int x)
|
|||||||
return values[x];
|
return values[x];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int64_t exp10_i64(int x)
|
constexpr inline int64_t exp10_i64(int x)
|
||||||
{
|
{
|
||||||
static const int64_t values[] = {
|
constexpr int64_t values[] =
|
||||||
1ll,
|
{
|
||||||
10ll,
|
1LL,
|
||||||
100ll,
|
10LL,
|
||||||
1000ll,
|
100LL,
|
||||||
10000ll,
|
1000LL,
|
||||||
100000ll,
|
10000LL,
|
||||||
1000000ll,
|
100000LL,
|
||||||
10000000ll,
|
1000000LL,
|
||||||
100000000ll,
|
10000000LL,
|
||||||
1000000000ll,
|
100000000LL,
|
||||||
10000000000ll,
|
1000000000LL,
|
||||||
100000000000ll,
|
10000000000LL,
|
||||||
1000000000000ll,
|
100000000000LL,
|
||||||
10000000000000ll,
|
1000000000000LL,
|
||||||
100000000000000ll,
|
10000000000000LL,
|
||||||
1000000000000000ll,
|
100000000000000LL,
|
||||||
10000000000000000ll,
|
1000000000000000LL,
|
||||||
100000000000000000ll,
|
10000000000000000LL,
|
||||||
1000000000000000000ll
|
100000000000000000LL,
|
||||||
|
1000000000000000000LL
|
||||||
};
|
};
|
||||||
return values[x];
|
return values[x];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline __int128 exp10_i128(int x)
|
constexpr inline __int128 exp10_i128(int x)
|
||||||
{
|
{
|
||||||
static const __int128 values[] = {
|
constexpr __int128 values[] =
|
||||||
static_cast<__int128>(1ll),
|
{
|
||||||
static_cast<__int128>(10ll),
|
static_cast<__int128>(1LL),
|
||||||
static_cast<__int128>(100ll),
|
static_cast<__int128>(10LL),
|
||||||
static_cast<__int128>(1000ll),
|
static_cast<__int128>(100LL),
|
||||||
static_cast<__int128>(10000ll),
|
static_cast<__int128>(1000LL),
|
||||||
static_cast<__int128>(100000ll),
|
static_cast<__int128>(10000LL),
|
||||||
static_cast<__int128>(1000000ll),
|
static_cast<__int128>(100000LL),
|
||||||
static_cast<__int128>(10000000ll),
|
static_cast<__int128>(1000000LL),
|
||||||
static_cast<__int128>(100000000ll),
|
static_cast<__int128>(10000000LL),
|
||||||
static_cast<__int128>(1000000000ll),
|
static_cast<__int128>(100000000LL),
|
||||||
static_cast<__int128>(10000000000ll),
|
static_cast<__int128>(1000000000LL),
|
||||||
static_cast<__int128>(100000000000ll),
|
static_cast<__int128>(10000000000LL),
|
||||||
static_cast<__int128>(1000000000000ll),
|
static_cast<__int128>(100000000000LL),
|
||||||
static_cast<__int128>(10000000000000ll),
|
static_cast<__int128>(1000000000000LL),
|
||||||
static_cast<__int128>(100000000000000ll),
|
static_cast<__int128>(10000000000000LL),
|
||||||
static_cast<__int128>(1000000000000000ll),
|
static_cast<__int128>(100000000000000LL),
|
||||||
static_cast<__int128>(10000000000000000ll),
|
static_cast<__int128>(1000000000000000LL),
|
||||||
static_cast<__int128>(100000000000000000ll),
|
static_cast<__int128>(10000000000000000LL),
|
||||||
static_cast<__int128>(1000000000000000000ll),
|
static_cast<__int128>(100000000000000000LL),
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10ll,
|
static_cast<__int128>(1000000000000000000LL),
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100ll,
|
static_cast<__int128>(1000000000000000000LL) * 10LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 1000ll,
|
static_cast<__int128>(1000000000000000000LL) * 100LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10000ll,
|
static_cast<__int128>(1000000000000000000LL) * 1000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000ll,
|
static_cast<__int128>(1000000000000000000LL) * 10000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 1000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 1000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 10000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 1000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 1000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 10000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 1000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 1000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 10000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 1000000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 10000000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 1000000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000000000ll,
|
static_cast<__int128>(1000000000000000000LL) * 10000000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000000000ll * 10ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000000000000000LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000000000ll * 100ll,
|
static_cast<__int128>(1000000000000000000LL) * 100000000000000000LL * 10LL,
|
||||||
static_cast<__int128>(1000000000000000000ll) * 100000000000000000ll * 1000ll
|
static_cast<__int128>(1000000000000000000LL) * 100000000000000000LL * 100LL,
|
||||||
|
static_cast<__int128>(1000000000000000000LL) * 100000000000000000LL * 1000LL
|
||||||
};
|
};
|
||||||
return values[x];
|
return values[x];
|
||||||
}
|
}
|
||||||
@ -138,7 +141,7 @@ inline __int128 exp10_i128(int x)
|
|||||||
|
|
||||||
/// intExp10 returning the type T.
|
/// intExp10 returning the type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T intExp10OfSize(int x)
|
constexpr inline T intExp10OfSize(int x)
|
||||||
{
|
{
|
||||||
if constexpr (sizeof(T) <= 8)
|
if constexpr (sizeof(T) <= 8)
|
||||||
return intExp10(x);
|
return intExp10(x);
|
||||||
|
@ -20,19 +20,34 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int ARGUMENT_OUT_OF_BOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr UInt32 max_scale = 9;
|
||||||
|
|
||||||
DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name)
|
DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const std::string & time_zone_name)
|
||||||
: DataTypeDecimalBase<DateTime64>(DecimalUtils::maxPrecision<DateTime64>(), scale_),
|
: DataTypeDecimalBase<DateTime64>(DecimalUtils::maxPrecision<DateTime64>(), scale_),
|
||||||
TimezoneMixin(time_zone_name)
|
TimezoneMixin(time_zone_name)
|
||||||
{
|
{
|
||||||
|
if (scale > max_scale)
|
||||||
|
throw Exception("Scale " + std::to_string(scale) + " is too large for DateTime64. Maximum is up to nanoseconds (9).",
|
||||||
|
ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const TimezoneMixin & time_zone_info)
|
DataTypeDateTime64::DataTypeDateTime64(UInt32 scale_, const TimezoneMixin & time_zone_info)
|
||||||
: DataTypeDecimalBase<DateTime64>(DecimalUtils::maxPrecision<DateTime64>() - scale_, scale_),
|
: DataTypeDecimalBase<DateTime64>(DecimalUtils::maxPrecision<DateTime64>(), scale_),
|
||||||
TimezoneMixin(time_zone_info)
|
TimezoneMixin(time_zone_info)
|
||||||
{}
|
{
|
||||||
|
if (scale > max_scale)
|
||||||
|
throw Exception("Scale " + std::to_string(scale) + " is too large for DateTime64. Maximum is up to nanoseconds (9).",
|
||||||
|
ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
|
}
|
||||||
|
|
||||||
std::string DataTypeDateTime64::doGetName() const
|
std::string DataTypeDateTime64::doGetName() const
|
||||||
{
|
{
|
||||||
|
@ -72,7 +72,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (unlikely(precision < 1 || precision > maxPrecision()))
|
if (unlikely(precision < 1 || precision > maxPrecision()))
|
||||||
throw Exception("Precision " + std::to_string(precision) + " is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception("Precision " + std::to_string(precision) + " is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
if (unlikely(scale < 0 || static_cast<UInt32>(scale) > maxPrecision()))
|
if (unlikely(scale > maxPrecision()))
|
||||||
throw Exception("Scale " + std::to_string(scale) + " is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception("Scale " + std::to_string(scale) + " is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ DataTypePtr getLeastSupertype(const DataTypes & types)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For Date and DateTime, the common type is DateTime. No other types are compatible.
|
/// For Date and DateTime/DateTime64, the common type is DateTime/DateTime64. No other types are compatible.
|
||||||
{
|
{
|
||||||
UInt32 have_date = type_ids.count(TypeIndex::Date);
|
UInt32 have_date = type_ids.count(TypeIndex::Date);
|
||||||
UInt32 have_datetime = type_ids.count(TypeIndex::DateTime);
|
UInt32 have_datetime = type_ids.count(TypeIndex::DateTime);
|
||||||
@ -218,40 +218,25 @@ DataTypePtr getLeastSupertype(const DataTypes & types)
|
|||||||
{
|
{
|
||||||
bool all_date_or_datetime = type_ids.size() == (have_date + have_datetime + have_datetime64);
|
bool all_date_or_datetime = type_ids.size() == (have_date + have_datetime + have_datetime64);
|
||||||
if (!all_date_or_datetime)
|
if (!all_date_or_datetime)
|
||||||
throw Exception(getExceptionMessagePrefix(types) + " because some of them are Date/DateTime and some of them are not", ErrorCodes::NO_COMMON_TYPE);
|
throw Exception(getExceptionMessagePrefix(types) + " because some of them are Date/DateTime/DateTime64 and some of them are not",
|
||||||
|
ErrorCodes::NO_COMMON_TYPE);
|
||||||
|
|
||||||
if (have_datetime64 == 0)
|
if (have_datetime64 == 0)
|
||||||
{
|
|
||||||
return std::make_shared<DataTypeDateTime>();
|
return std::make_shared<DataTypeDateTime>();
|
||||||
}
|
|
||||||
|
|
||||||
// When DateTime64 involved, make sure that supertype has whole-part precision
|
UInt8 max_scale = 0;
|
||||||
// big enough to hold max whole-value of any type from `types`.
|
|
||||||
// That would sacrifice scale when comparing DateTime64 of different scales.
|
|
||||||
|
|
||||||
UInt32 max_datetime64_whole_precision = 0;
|
|
||||||
for (const auto & t : types)
|
for (const auto & t : types)
|
||||||
{
|
{
|
||||||
if (const auto * dt64 = typeid_cast<const DataTypeDateTime64 *>(t.get()))
|
if (const auto * dt64 = typeid_cast<const DataTypeDateTime64 *>(t.get()))
|
||||||
{
|
{
|
||||||
const auto whole_precision = dt64->getPrecision() - dt64->getScale();
|
const auto scale = dt64->getScale();
|
||||||
max_datetime64_whole_precision = std::max(whole_precision, max_datetime64_whole_precision);
|
if (scale > max_scale)
|
||||||
|
max_scale = scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 least_decimal_precision = 0;
|
return std::make_shared<DataTypeDateTime64>(max_scale);
|
||||||
if (have_datetime)
|
|
||||||
{
|
|
||||||
least_decimal_precision = leastDecimalPrecisionFor(TypeIndex::UInt32);
|
|
||||||
}
|
|
||||||
else if (have_date)
|
|
||||||
{
|
|
||||||
least_decimal_precision = leastDecimalPrecisionFor(TypeIndex::UInt16);
|
|
||||||
}
|
|
||||||
max_datetime64_whole_precision = std::max(least_decimal_precision, max_datetime64_whole_precision);
|
|
||||||
|
|
||||||
const UInt32 scale = DataTypeDateTime64::maxPrecision() - max_datetime64_whole_precision;
|
|
||||||
return std::make_shared<DataTypeDateTime64>(scale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ TEST_P(LeastSuperTypeTest, getLeastSupertype)
|
|||||||
|
|
||||||
class MostSubtypeTest : public TypeTest {};
|
class MostSubtypeTest : public TypeTest {};
|
||||||
|
|
||||||
TEST_P(MostSubtypeTest, getLeastSupertype)
|
TEST_P(MostSubtypeTest, getMostSubtype)
|
||||||
{
|
{
|
||||||
if (this->expected_type)
|
if (this->expected_type)
|
||||||
{
|
{
|
||||||
@ -124,9 +124,7 @@ INSTANTIATE_TEST_SUITE_P(data_type,
|
|||||||
{"Date DateTime64(3)", "DateTime64(3)"},
|
{"Date DateTime64(3)", "DateTime64(3)"},
|
||||||
{"DateTime DateTime64(3)", "DateTime64(3)"},
|
{"DateTime DateTime64(3)", "DateTime64(3)"},
|
||||||
{"DateTime DateTime64(0)", "DateTime64(0)"},
|
{"DateTime DateTime64(0)", "DateTime64(0)"},
|
||||||
{"DateTime64(9) DateTime64(3)", "DateTime64(3)"},
|
{"DateTime64(9) DateTime64(3)", "DateTime64(9)"},
|
||||||
{"DateTime DateTime64(12)", "DateTime64(8)"},
|
|
||||||
{"Date DateTime64(15)", "DateTime64(13)"},
|
|
||||||
|
|
||||||
{"String FixedString(32) FixedString(8)", "String"},
|
{"String FixedString(32) FixedString(8)", "String"},
|
||||||
|
|
||||||
|
@ -275,8 +275,11 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
|
|||||||
switch (*buf.position())
|
switch (*buf.position())
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case '-':
|
case '-':
|
||||||
|
{
|
||||||
if constexpr (is_signed_v<T>)
|
if constexpr (is_signed_v<T>)
|
||||||
negative = true;
|
negative = true;
|
||||||
else
|
else
|
||||||
@ -287,6 +290,7 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
|
|||||||
return ReturnType(false);
|
return ReturnType(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case '0': [[fallthrough]];
|
case '0': [[fallthrough]];
|
||||||
case '1': [[fallthrough]];
|
case '1': [[fallthrough]];
|
||||||
case '2': [[fallthrough]];
|
case '2': [[fallthrough]];
|
||||||
@ -297,20 +301,27 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
|
|||||||
case '7': [[fallthrough]];
|
case '7': [[fallthrough]];
|
||||||
case '8': [[fallthrough]];
|
case '8': [[fallthrough]];
|
||||||
case '9':
|
case '9':
|
||||||
|
{
|
||||||
if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW)
|
if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW)
|
||||||
{
|
{
|
||||||
// perform relativelly slow overflow check only when number of decimal digits so far is close to the max for given type.
|
/// Perform relativelly slow overflow check only when
|
||||||
if (buf.count() - initial_pos >= std::numeric_limits<T>::max_digits10)
|
/// number of decimal digits so far is close to the max for given type.
|
||||||
|
/// Example: 20 * 10 will overflow Int8.
|
||||||
|
|
||||||
|
if (buf.count() - initial_pos + 1 >= std::numeric_limits<T>::max_digits10)
|
||||||
{
|
{
|
||||||
if (common::mulOverflow(res, static_cast<decltype(res)>(10), res)
|
T signed_res = res;
|
||||||
|| common::addOverflow(res, static_cast<decltype(res)>(*buf.position() - '0'), res))
|
if (common::mulOverflow<T>(signed_res, 10, signed_res)
|
||||||
|
|| common::addOverflow<T>(signed_res, (*buf.position() - '0'), signed_res))
|
||||||
return ReturnType(false);
|
return ReturnType(false);
|
||||||
|
res = signed_res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res *= 10;
|
res *= 10;
|
||||||
res += *buf.position() - '0';
|
res += *buf.position() - '0';
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -318,7 +329,23 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
x = negative ? -res : res;
|
if (!negative)
|
||||||
|
{
|
||||||
|
x = res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW)
|
||||||
|
{
|
||||||
|
x = res;
|
||||||
|
if (common::mulOverflow<T>(x, -1, x))
|
||||||
|
return ReturnType(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = -res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ReturnType(true);
|
return ReturnType(true);
|
||||||
}
|
}
|
||||||
@ -658,35 +685,34 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
|
|||||||
return ReturnType(false);
|
return ReturnType(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::DecimalUtils::DecimalComponents<DateTime64::NativeType> c{static_cast<DateTime64::NativeType>(whole), 0};
|
DB::DecimalUtils::DecimalComponents<DateTime64::NativeType> components{static_cast<DateTime64::NativeType>(whole), 0};
|
||||||
|
|
||||||
if (!buf.eof() && *buf.position() == '.')
|
if (!buf.eof() && *buf.position() == '.')
|
||||||
{
|
{
|
||||||
buf.ignore(1); // skip separator
|
++buf.position();
|
||||||
const auto pos_before_fractional = buf.count();
|
|
||||||
if (!tryReadIntText<ReadIntTextCheckOverflow::CHECK_OVERFLOW>(c.fractional, buf))
|
|
||||||
{
|
|
||||||
return ReturnType(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust fractional part to the scale, since decimalFromComponents knows nothing
|
/// Read digits, up to 'scale' positions.
|
||||||
// about convention of ommiting trailing zero on fractional part
|
for (size_t i = 0; i < scale; ++i)
|
||||||
// and assumes that fractional part value is less than 10^scale.
|
|
||||||
|
|
||||||
// If scale is 3, but we read '12', promote fractional part to '120'.
|
|
||||||
// And vice versa: if we read '1234', denote it to '123'.
|
|
||||||
const auto fractional_length = static_cast<Int32>(buf.count() - pos_before_fractional);
|
|
||||||
if (const auto adjust_scale = static_cast<Int32>(scale) - fractional_length; adjust_scale > 0)
|
|
||||||
{
|
{
|
||||||
c.fractional *= common::exp10_i64(adjust_scale);
|
if (!buf.eof() && isNumericASCII(*buf.position()))
|
||||||
|
{
|
||||||
|
components.fractional *= 10;
|
||||||
|
components.fractional += *buf.position() - '0';
|
||||||
|
++buf.position();
|
||||||
}
|
}
|
||||||
else if (adjust_scale < 0)
|
else
|
||||||
{
|
{
|
||||||
c.fractional /= common::exp10_i64(-1 * adjust_scale);
|
/// Adjust to scale.
|
||||||
|
components.fractional *= 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime64 = DecimalUtils::decimalFromComponents<DateTime64>(c, scale);
|
/// Ignore digits that are out of precision.
|
||||||
|
while (!buf.eof() && isNumericASCII(*buf.position()))
|
||||||
|
++buf.position();
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime64 = DecimalUtils::decimalFromComponents<DateTime64>(components, scale);
|
||||||
|
|
||||||
return ReturnType(true);
|
return ReturnType(true);
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
select now64(10); -- { serverError 407 }
|
select now64(10); -- { serverError 69 }
|
||||||
select length(toString(now64(9)));
|
select length(toString(now64(9)));
|
||||||
|
@ -6,7 +6,7 @@ WITH '2020-02-05 14:34:12.333' as S, toDateTime64(S, 3) as DT64 SELECT * WHERE D
|
|||||||
WITH '2020-02-05 14:34:12.333' as S, toDateTime64(S, 3) as DT64 SELECT * WHERE materialize(S) = DT64; -- {serverError 43}
|
WITH '2020-02-05 14:34:12.333' as S, toDateTime64(S, 3) as DT64 SELECT * WHERE materialize(S) = DT64; -- {serverError 43}
|
||||||
|
|
||||||
SELECT * WHERE toDateTime64(123.345, 3) == 'ABCD'; -- {serverError 53} -- invalid DateTime64 string
|
SELECT * WHERE toDateTime64(123.345, 3) == 'ABCD'; -- {serverError 53} -- invalid DateTime64 string
|
||||||
SELECT * WHERE toDateTime64(123.345, 3) == '2020-02-05 14:34:12.33333333333333333333333333333333333333333333333333333333'; -- {serverError 53} -- invalid string length
|
SELECT * WHERE toDateTime64(123.345, 3) == '2020-02-05 14:34:12.33333333333333333333333333333333333333333333333333333333';
|
||||||
|
|
||||||
SELECT 'in SELECT';
|
SELECT 'in SELECT';
|
||||||
WITH '2020-02-05 14:34:12.333' as S, toDateTime64(S, 3) as DT64 SELECT DT64 = S;
|
WITH '2020-02-05 14:34:12.333' as S, toDateTime64(S, 3) as DT64 SELECT DT64 = S;
|
||||||
|
22
tests/queries/0_stateless/01340_datetime64_fpe.reference
Normal file
22
tests/queries/0_stateless/01340_datetime64_fpe.reference
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
||||||
|
2011-11-11 11:11:11
|
71
tests/queries/0_stateless/01340_datetime64_fpe.sql
Normal file
71
tests/queries/0_stateless/01340_datetime64_fpe.sql
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
WITH toDateTime64('2019-09-16 19:20:12.3456789102019-09-16 19:20:12.345678910', 0) AS dt64 SELECT dt64; -- { serverError 6 }
|
||||||
|
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1234567890123456789', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-12345678901234567890', 0); -- { serverError 6 }
|
||||||
|
|
||||||
|
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.1111111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.11111111111111111111', 0);
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.111111111111111111111', 0);
|
||||||
|
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-1111111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-11111111111111111111', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.-111111111111111111111', 0); -- { serverError 6 }
|
||||||
|
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+1', 0); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.++11', 10); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+111', 3); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+++1111', 5); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+11111', 7); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+++++111111', 2); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+1111111', 1); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.++++++11111111', 8); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+111111111', 9); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+++++++1111111111', 6); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+11111111111', 4); -- { serverError 6 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.++++++++111111111111', 11); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+1111111111111', 15); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+++++++++11111111111111', 13); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+111111111111111', 12); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.++++++++++1111111111111111', 16); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+11111111111111111', 14); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+++++++++++111111111111111111', 15); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+1111111111111111111', 17); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.++++++++++++11111111111111111111', 19); -- { serverError 69 }
|
||||||
|
SELECT toDateTime64('2011-11-11 11:11:11.+111111111111111111111', 18); -- { serverError 69 }
|
@ -0,0 +1 @@
|
|||||||
|
['2000-01-01 01:01:01.123000','2000-01-01 01:01:01.123456']
|
@ -0,0 +1 @@
|
|||||||
|
SELECT [toDateTime64('2000-01-01 01:01:01.123', 3), toDateTime64('2000-01-01 01:01:01.123456', 6)];
|
Loading…
Reference in New Issue
Block a user