From 252268ef638bebfd786ce9d97c789dc7755dc0cc Mon Sep 17 00:00:00 2001 From: jmrojas2332 Date: Tue, 3 Dec 2019 06:47:36 +0000 Subject: [PATCH] MCOL 3474 Fix TIMEDIFF w/ non-temporal data types --- utils/funcexp/func_timediff.cpp | 75 +++++++++++++++++++++++++++------ utils/funcexp/funchelpers.h | 32 +++++++------- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/utils/funcexp/func_timediff.cpp b/utils/funcexp/func_timediff.cpp index cbd839389..729045798 100644 --- a/utils/funcexp/func_timediff.cpp +++ b/utils/funcexp/func_timediff.cpp @@ -45,7 +45,7 @@ namespace funcexp namespace helpers { -const string timediff( int64_t time1, int64_t time2) +const string timediff( int64_t time1, int64_t time2, bool isDateTime) { long long seconds; long long microseconds; @@ -56,9 +56,9 @@ const string timediff( int64_t time1, int64_t time2) l_sign = -l_sign; if ( time1 > time2 ) - helpers::calc_time_diff(time1, time2, l_sign, &seconds, µseconds); + helpers::calc_time_diff(time1, time2, l_sign, &seconds, µseconds, isDateTime); else - helpers::calc_time_diff(time2, time1, l_sign, &seconds, µseconds); + helpers::calc_time_diff(time2, time1, l_sign, &seconds, µseconds, isDateTime); long t_seconds; int hour = seconds / 3600L; @@ -162,8 +162,20 @@ string Func_timediff::getStrVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::CHAR: case execplan::CalpontSystemCatalog::TEXT: text = parm[0]->data()->getStrVal(row, isNull); - isTime1 = std::count(text.begin(), text.end(), '-') <= 1; // Time can have at most 1 dash (signifies negative) - val1 = dataconvert::DataConvert::stringToDatetime(text, &isDate1); + + if (text.length() >= 14) // datetime has length at least 14 + { + val1 = dataconvert::DataConvert::stringToDatetime(text, &isDate1); + } + else if (text.length() == 8 && text.find("-") == string::npos && text.find(":") == string::npos) // special case, this is exactly a date + { + val1 = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull), &isDate1); + } + else + { + val1 = dataconvert::DataConvert::stringToTime(text); + isTime1 = true; + } break; case execplan::CalpontSystemCatalog::BIGINT: @@ -171,7 +183,14 @@ string Func_timediff::getStrVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::SMALLINT: - val1 = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull), &isDate1); + text = parm[0]->data()->getStrVal(row, isNull); + if (text.length() >= 14) // datetime has length at least 14 + val1 = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull), &isDate1); + else + { + val1 = dataconvert::DataConvert::intToTime(parm[0]->data()->getIntVal(row, isNull)); + isTime1 = true; + } break; case execplan::CalpontSystemCatalog::DECIMAL: @@ -182,7 +201,14 @@ string Func_timediff::getStrVal(rowgroup::Row& row, } else { - val1 = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull), &isDate1); + text = parm[0]->data()->getStrVal(row, isNull); + if (text.length() >= 14) // datetime has length at least 14 + val1 = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull), &isDate1); + else + { + val1 = dataconvert::DataConvert::intToTime(parm[0]->data()->getIntVal(row, isNull)); + isTime1 = true; + } break; } @@ -226,8 +252,19 @@ string Func_timediff::getStrVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::CHAR: case execplan::CalpontSystemCatalog::TEXT: text = parm[1]->data()->getStrVal(row, isNull); - isTime2 = std::count(text.begin(), text.end(), '-') <= 1; // Time can have at most 1 dash (signifies negative) - val2 = dataconvert::DataConvert::stringToDatetime(text, &isDate2); + if (text.length() >= 14) // datetime has length at least 14 + { + val2 = dataconvert::DataConvert::stringToDatetime(text, &isDate2); + } + else if (text.length() == 8 && text.find("-") == string::npos && text.find(":") == string::npos) // special case, this is exactly a date + { + val2 = dataconvert::DataConvert::intToDatetime(parm[1]->data()->getIntVal(row, isNull), &isDate2); + } + else + { + val2 = dataconvert::DataConvert::stringToTime(text); + isTime2 = true; + } break; case execplan::CalpontSystemCatalog::BIGINT: @@ -235,7 +272,14 @@ string Func_timediff::getStrVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::SMALLINT: - val2 = dataconvert::DataConvert::intToDatetime(parm[1]->data()->getIntVal(row, isNull), &isDate2); + text = parm[1]->data()->getStrVal(row, isNull); + if (text.length() >= 14) // datetime has length at least 14 + val2 = dataconvert::DataConvert::intToDatetime(parm[1]->data()->getIntVal(row, isNull), &isDate2); + else + { + val2 = dataconvert::DataConvert::intToTime(parm[1]->data()->getIntVal(row, isNull)); + isTime2 = true; + } break; case execplan::CalpontSystemCatalog::DECIMAL: @@ -246,7 +290,14 @@ string Func_timediff::getStrVal(rowgroup::Row& row, } else { - val2 = dataconvert::DataConvert::intToDatetime(parm[1]->data()->getIntVal(row, isNull), &isDate2); + text = parm[1]->data()->getStrVal(row, isNull); + if (text.length() >= 14) // datetime has length at least 14 + val2 = dataconvert::DataConvert::intToDatetime(parm[1]->data()->getIntVal(row, isNull), &isDate2); + else + { + val2 = dataconvert::DataConvert::intToTime(parm[1]->data()->getIntVal(row, isNull)); + isTime2 = true; + } break; } @@ -262,7 +313,7 @@ string Func_timediff::getStrVal(rowgroup::Row& row, // both date format or both datetime format. Diff between time and datetime returns NULL in MariaDB if ((isDate1 && isDate2) || ((!isDate1 && !isDate2) && (isTime1 == isTime2))) - return helpers::timediff( val1, val2); + return helpers::timediff( val1, val2, !isTime1); isNull = true; return ""; diff --git a/utils/funcexp/funchelpers.h b/utils/funcexp/funchelpers.h index e579ebb57..b240477b2 100644 --- a/utils/funcexp/funchelpers.h +++ b/utils/funcexp/funchelpers.h @@ -371,7 +371,7 @@ inline uint32_t calc_mysql_week( uint32_t year, uint32_t month, uint32_t day, return days / 7 + 1; } -inline bool calc_time_diff(int64_t time1, int64_t time2, int l_sign, long long* seconds_out, long long* microseconds_out) +inline bool calc_time_diff(int64_t time1, int64_t time2, int l_sign, long long* seconds_out, long long* microseconds_out, bool isDateTime = true) { int64_t days; bool neg; @@ -393,21 +393,21 @@ inline bool calc_time_diff(int64_t time1, int64_t time2, int l_sign, long long* sec2 = 0, msec2 = 0; - year1 = (uint32_t)((time1 >> 48) & 0xffff); - month1 = (uint32_t)((time1 >> 44) & 0xf); - day1 = (uint32_t)((time1 >> 38) & 0x3f); - hour1 = (uint32_t)((time1 >> 32) & 0x3f); - min1 = (uint32_t)((time1 >> 26) & 0x3f); - sec1 = (uint32_t)((time1 >> 20) & 0x3f); - msec1 = (uint32_t)((time1 & 0xfffff)); + year1 = isDateTime ? (uint32_t)((time1 >> 48) & 0xffff) : 0; + month1 = isDateTime ? (uint32_t)((time1 >> 44) & 0xf) : 0; + day1 = isDateTime ? (uint32_t)((time1 >> 38) & 0x3f) : (uint32_t)((time1 >> 52) & 0x7ff); + hour1 = isDateTime ? (uint32_t)((time1 >> 32) & 0x3f) : (uint32_t)((time1 >> 40) & 0xfff); + min1 = isDateTime ? (uint32_t)((time1 >> 26) & 0x3f) : (uint32_t)((time1 >> 32) & 0xff); + sec1 = isDateTime ? (uint32_t)((time1 >> 20) & 0x3f) : (uint32_t)((time1 >> 24) & 0xff); + msec1 = isDateTime ? (uint32_t)((time1 & 0xfffff)) : (uint32_t)(time1 & 0xffffff); - year2 = (uint32_t)((time2 >> 48) & 0xffff); - month2 = (uint32_t)((time2 >> 44) & 0xf); - day2 = (uint32_t)((time2 >> 38) & 0x3f); - hour2 = (uint32_t)((time2 >> 32) & 0x3f); - min2 = (uint32_t)((time2 >> 26) & 0x3f); - sec2 = (uint32_t)((time2 >> 20) & 0x3f); - msec2 = (uint32_t)((time2 & 0xfffff)); + year2 = isDateTime ? (uint32_t)((time2 >> 48) & 0xffff) : 0; + month2 = isDateTime ? (uint32_t)((time2 >> 44) & 0xf) : 0; + day2 = isDateTime ? (uint32_t)((time2 >> 38) & 0x3f) : (uint32_t)((time2 >> 52) & 0x7ff);; + hour2 = isDateTime ? (uint32_t)((time2 >> 32) & 0x3f) : (uint32_t)((time2 >> 40) & 0xfff); + min2 = isDateTime ? (uint32_t)((time2 >> 26) & 0x3f) : (uint32_t)((time2 >> 32) & 0xff); + sec2 = isDateTime ? (uint32_t)((time2 >> 20) & 0x3f) : (uint32_t)((time2 >> 24) & 0xff); + msec2 = isDateTime ? (uint32_t)((time2 & 0xfffff)) : (uint32_t)(time2 & 0xffffff); days = calc_mysql_daynr(year1, month1, day1); @@ -768,7 +768,7 @@ string longDoubleToString(long double ld) uint64_t dateAdd( uint64_t time, const std::string& expr, execplan::IntervalColumn::interval_type unit, bool dateType, execplan::OpType funcType ); const std::string IDB_date_format(const dataconvert::DateTime&, const std::string&); -const std::string timediff(int64_t, int64_t); +const std::string timediff(int64_t, int64_t, bool isDateTime = true); const char* convNumToStr(int64_t, char*, int); } //namespace funcexp::helpers