This commit is contained in:
nikitamikhaylov 2020-12-08 21:28:18 +03:00
parent e3a9cae4c5
commit 95ce4bc54c
4 changed files with 39 additions and 50 deletions

View File

@ -149,17 +149,14 @@ namespace DB
/* Implementation */ /* Implementation */
namespace gd { namespace gd
{
using namespace DB; using namespace DB;
template <typename YearT> template <typename YearT>
static inline constexpr bool isLeapYear(YearT year) static inline constexpr bool isLeapYear(YearT year)
{ {
return ( (year % 4 == 0) return (year % 4 == 0) && ((year % 400 == 0) || (year % 100 != 0));
&&
( (year % 400 == 0)
||
(! (year % 100 == 0)) ) );
} }
static inline constexpr uint8_t monthLength(bool isLeapYear, uint8_t month) static inline constexpr uint8_t monthLength(bool isLeapYear, uint8_t month)
@ -189,15 +186,12 @@ namespace gd {
static inline constexpr I div(I x, J y) static inline constexpr I div(I x, J y)
{ {
const auto y_ = static_cast<I>(y); const auto y_ = static_cast<I>(y);
if (x > 0 && y_ < 0) { if (x > 0 && y_ < 0)
return ((x - 1) / y_) - 1; return ((x - 1) / y_) - 1;
} else if (x < 0 && y_ > 0)
else if (x < 0 && y_ > 0) {
return ((x + 1) / y_) - 1; return ((x + 1) / y_) - 1;
} else
else {
return x / y_; return x / y_;
}
} }
/** Integer modulus, satisfying div(x, y)*y + mod(x, y) == x. /** Integer modulus, satisfying div(x, y)*y + mod(x, y) == x.
@ -207,12 +201,10 @@ namespace gd {
{ {
const auto y_ = static_cast<I>(y); const auto y_ = static_cast<I>(y);
const auto r = x % y_; const auto r = x % y_;
if ((x > 0 && y_ < 0) || (x < 0 && y_ > 0)) { if ((x > 0 && y_ < 0) || (x < 0 && y_ > 0))
return r == 0 ? static_cast<I>(0) : r + y_; return r == 0 ? static_cast<I>(0) : r + y_;
} else
else {
return r; return r;
}
} }
/** Like std::min(), but the type of operands may differ. /** Like std::min(), but the type of operands may differ.
@ -227,19 +219,16 @@ namespace gd {
static inline char readDigit(ReadBuffer & in) static inline char readDigit(ReadBuffer & in)
{ {
char c; char c;
if (!in.read(c)) { if (!in.read(c))
throw Exception( throw Exception(
"Cannot parse input: expected a digit at the end of stream", "Cannot parse input: expected a digit at the end of stream",
ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED); ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED);
} else if (c < '0' || c > '9')
else if (c < '0' || c > '9') {
throw Exception( throw Exception(
"Cannot read input: expected a digit but got something else", "Cannot read input: expected a digit but got something else",
ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED); ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED);
} else
else {
return c - '0'; return c - '0';
}
} }
} }
@ -303,7 +292,8 @@ namespace DB
"Impossible to stringify: year too big or small: " + DB::toString(year_), "Impossible to stringify: year too big or small: " + DB::toString(year_),
ErrorCodes::CANNOT_FORMAT_DATETIME); ErrorCodes::CANNOT_FORMAT_DATETIME);
} }
else { else
{
auto y = year_; auto y = year_;
writeChar('0' + y / 1000, buf); y %= 1000; writeChar('0' + y / 1000, buf); y %= 1000;
writeChar('0' + y / 100, buf); y %= 100; writeChar('0' + y / 100, buf); y %= 100;
@ -367,22 +357,21 @@ namespace DB
{ {
const auto y = year_ - 1; const auto y = year_ - 1;
return dayOfYear_ return dayOfYear_
+ 365 * y + 365 * y
+ gd::div(y, 4) + gd::div(y, 4)
- gd::div(y, 100) - gd::div(y, 100)
+ gd::div(y, 400) + gd::div(y, 400)
- 678576; - 678576;
} }
inline MonthDay::MonthDay(uint8_t month, uint8_t dayOfMonth) inline MonthDay::MonthDay(uint8_t month, uint8_t dayOfMonth)
: month_(month) : month_(month)
, dayOfMonth_(dayOfMonth) , dayOfMonth_(dayOfMonth)
{ {
if (month < 1 || month > 12) { if (month < 1 || month > 12)
throw Exception( throw Exception(
"Invalid month: " + DB::toString(month), "Invalid month: " + DB::toString(month),
ErrorCodes::LOGICAL_ERROR); ErrorCodes::LOGICAL_ERROR);
}
/* We can't validate dayOfMonth here, because we don't know if /* We can't validate dayOfMonth here, because we don't know if
* it's a leap year. */ * it's a leap year. */
} }
@ -390,25 +379,20 @@ namespace DB
inline MonthDay::MonthDay(bool isLeapYear, uint16_t dayOfYear) inline MonthDay::MonthDay(bool isLeapYear, uint16_t dayOfYear)
{ {
if (dayOfYear < 1 || dayOfYear > (isLeapYear ? 366 : 365)) if (dayOfYear < 1 || dayOfYear > (isLeapYear ? 366 : 365))
{
throw Exception( throw Exception(
std::string("Invalid day of year: ") + std::string("Invalid day of year: ") +
(isLeapYear ? "leap, " : "non-leap, ") + DB::toString(dayOfYear), (isLeapYear ? "leap, " : "non-leap, ") + DB::toString(dayOfYear),
ErrorCodes::LOGICAL_ERROR); ErrorCodes::LOGICAL_ERROR);
}
month_ = 1; month_ = 1;
uint16_t d = dayOfYear; uint16_t d = dayOfYear;
while (true) { while (true)
{
const auto len = gd::monthLength(isLeapYear, month_); const auto len = gd::monthLength(isLeapYear, month_);
if (d > len) if (d <= len)
{
month_++;
d -= len;
}
else {
break; break;
} month_++;
d -= len;
} }
dayOfMonth_ = d; dayOfMonth_ = d;
} }
@ -423,9 +407,7 @@ namespace DB
"-" + DB::toString(dayOfMonth_), "-" + DB::toString(dayOfMonth_),
ErrorCodes::LOGICAL_ERROR); ErrorCodes::LOGICAL_ERROR);
} }
const auto k = month_ <= 2 ? 0 const auto k = month_ <= 2 ? 0 : isLeapYear ? -1 :-2;
: isLeapYear ? -1
: -2;
return (367 * month_ - 362) / 12 + k + dayOfMonth_; return (367 * month_ - 362) / 12 + k + dayOfMonth_;
} }
} }

View File

@ -15,6 +15,13 @@
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int CANNOT_FORMAT_DATETIME;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
}
template <typename Name, typename FromDataType, bool nullOnErrors> template <typename Name, typename FromDataType, bool nullOnErrors>
class ExecutableFunctionFromModifiedJulianDay : public IExecutableFunctionImpl class ExecutableFunctionFromModifiedJulianDay : public IExecutableFunctionImpl
{ {
@ -58,18 +65,15 @@ namespace DB
catch (const Exception & e) catch (const Exception & e)
{ {
if (e.code() == ErrorCodes::CANNOT_FORMAT_DATETIME) if (e.code() == ErrorCodes::CANNOT_FORMAT_DATETIME)
{
(*vec_null_map_to)[i] = true; (*vec_null_map_to)[i] = true;
}
else else
{
throw; throw;
}
} }
writeChar(0, write_buffer); writeChar(0, write_buffer);
offsets_to[i] = write_buffer.count(); offsets_to[i] = write_buffer.count();
} }
else { else
{
const GregorianDate<> gd(vec_from[i]); const GregorianDate<> gd(vec_from[i]);
gd.write(write_buffer); gd.write(write_buffer);
writeChar(0, write_buffer); writeChar(0, write_buffer);
@ -192,11 +196,10 @@ namespace DB
{ {
return std::make_unique<FunctionBaseFromModifiedJulianDay<Name, DataTypeInt32, nullOnErrors>>(argument_types, return_type); return std::make_unique<FunctionBaseFromModifiedJulianDay<Name, DataTypeInt32, nullOnErrors>>(argument_types, return_type);
} }
else { else
// Should not happen. // Should not happen.
throw Exception( throw Exception(
"The argument of function " + getName() + " must be integral", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); "The argument of function " + getName() + " must be integral", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
} }
} }

View File

@ -17,6 +17,8 @@ namespace DB
{ {
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED;
extern const int CANNOT_PARSE_DATE;
} }
template <typename Name, typename ToDataType, bool nullOnErrors> template <typename Name, typename ToDataType, bool nullOnErrors>

View File

@ -247,6 +247,7 @@ SRCS(
formatReadableTimeDelta.cpp formatReadableTimeDelta.cpp
formatRow.cpp formatRow.cpp
formatString.cpp formatString.cpp
fromModifiedJulianDay.cpp
fromUnixTimestamp64Micro.cpp fromUnixTimestamp64Micro.cpp
fromUnixTimestamp64Milli.cpp fromUnixTimestamp64Milli.cpp
fromUnixTimestamp64Nano.cpp fromUnixTimestamp64Nano.cpp
@ -455,6 +456,7 @@ SRCS(
toISOYear.cpp toISOYear.cpp
toLowCardinality.cpp toLowCardinality.cpp
toMinute.cpp toMinute.cpp
toModifiedJulianDay.cpp
toMonday.cpp toMonday.cpp
toMonth.cpp toMonth.cpp
toNullable.cpp toNullable.cpp