diff --git a/dbcon/execplan/treenode.h b/dbcon/execplan/treenode.h index 08b8b43c8..3b2dd7200 100644 --- a/dbcon/execplan/treenode.h +++ b/dbcon/execplan/treenode.h @@ -996,12 +996,12 @@ inline int64_t TreeNode::getDatetimeIntVal() memcpy(&tt, &fResult.intVal, 8); // Note, this should probably be current date +/- time - if (tt.hour > 23) + if ((tt.hour > 23) && (!tt.is_neg)) { day = tt.hour / 24; tt.hour = tt.hour % 24; } - else if (tt.hour < 0) + else if ((tt.hour < 0) || (tt.is_neg)) { tt.hour = 0; } @@ -1023,7 +1023,7 @@ inline int64_t TreeNode::getTimeIntVal() dataconvert::DateTime dt; memcpy(&dt, &fResult.intVal, 8); - dataconvert::Time tt(0, dt.hour, dt.minute, dt.second, dt.msecond); + dataconvert::Time tt(0, dt.hour, dt.minute, dt.second, dt.msecond, false); memcpy(&fResult.intVal, &tt, 8); return fResult.intVal; } diff --git a/utils/dataconvert/dataconvert.cpp b/utils/dataconvert/dataconvert.cpp index 41dff9aa9..0ba1e4a87 100644 --- a/utils/dataconvert/dataconvert.cpp +++ b/utils/dataconvert/dataconvert.cpp @@ -1005,6 +1005,7 @@ bool mysql_str_to_time( const string& input, Time& output ) output.minute = 59; output.second = 59; output.msecond = 999999; + output.is_neg = 0; } else if (hour < -838) { @@ -1012,6 +1013,7 @@ bool mysql_str_to_time( const string& input, Time& output ) output.minute = 59; output.second = 59; output.msecond = 999999; + output.is_neg = 1; } // If neither of the above match then we return a 0 time else @@ -1025,6 +1027,7 @@ bool mysql_str_to_time( const string& input, Time& output ) output.minute = min; output.second = sec; output.msecond = usec; + output.is_neg = isNeg; return true; } @@ -1914,12 +1917,18 @@ int64_t DataConvert::convertColumnTime( inMinute = 0; inSecond = 0; inMicrosecond = 0; + bool isNeg = false; if ( datetimeFormat != CALPONTTIME_ENUM ) { status = -1; return value; } + if (p[0] == '-') + { + isNeg = true; + } + errno = 0; p = strtok_r(p, ":.", &savePoint); @@ -1981,6 +1990,7 @@ int64_t DataConvert::convertColumnTime( atime.minute = inMinute; atime.second = inSecond; atime.msecond = inMicrosecond; + atime.is_neg = isNeg; memcpy( &value, &atime, 8); } @@ -1994,6 +2004,7 @@ int64_t DataConvert::convertColumnTime( atime.minute = 59; atime.second = 59; atime.msecond = 999999; + atime.is_neg = false; memcpy( &value, &atime, 8); } else if (inHour < -838) @@ -2003,6 +2014,7 @@ int64_t DataConvert::convertColumnTime( atime.minute = 59; atime.second = 59; atime.msecond = 999999; + atime.is_neg = false; memcpy( &value, &atime, 8); } // If neither of the above match then we return a 0 time @@ -2084,8 +2096,15 @@ std::string DataConvert::timeToString( long long timevalue, long decimals ) Time dt(timevalue); const int TIMETOSTRING_LEN = 19; // (-H)HH:MM:SS.mmmmmm\0 char buf[TIMETOSTRING_LEN]; + char* outbuf = buf; - sprintf(buf, "%02d:%02d:%02d", dt.hour, dt.minute, dt.second); + if ((dt.hour >= 0) && dt.is_neg) + { + outbuf[0] = '-'; + outbuf++; + } + + sprintf(outbuf, "%02d:%02d:%02d", dt.hour, dt.minute, dt.second); if (dt.msecond && decimals) { size_t start = strlen(buf); @@ -2128,7 +2147,9 @@ std::string DataConvert::timeToString1( long long datetimevalue ) const int TIMETOSTRING1_LEN = 14; // HHMMSSmmmmmm\0 char buf[TIMETOSTRING1_LEN]; - sprintf(buf, "%02d%02d%02d%06d", dt.hour, dt.minute, dt.second, dt.msecond); + char* outbuf = buf; + + sprintf(outbuf, "%02d%02d%02d%06d", dt.hour, dt.minute, dt.second, dt.msecond); return buf; } @@ -2633,7 +2654,9 @@ int64_t DataConvert::intToDatetime(int64_t data, bool* date) int64_t DataConvert::intToTime(int64_t data) { char buf[21] = {0}; + char* bufread = buf; Time atime; + bool isNeg = false; if (data == 0) { @@ -2641,6 +2664,7 @@ int64_t DataConvert::intToTime(int64_t data) atime.minute = 0; atime.second = 0; atime.msecond = 0; + atime.is_neg = 0; return *(reinterpret_cast(&atime)); } @@ -2650,24 +2674,37 @@ int64_t DataConvert::intToTime(int64_t data) string hour, min, sec, msec; int64_t h = 0, minute = 0, s = 0, ms = 0; - switch (strlen(buf)) + if (bufread[0] == '-') { + isNeg = true; + bufread++; + } + + switch (strlen(bufread)) + { + case 7: + hour = string(bufread, 3); + min = string(bufread + 2, 2); + sec = string(bufread + 4, 2); + msec = string(bufread + 6, 6); + break; + case 6: - hour = string(buf, 2); - min = string(buf + 2, 2); - sec = string(buf + 4, 2); - msec = string(buf + 6, 6); + hour = string(bufread, 2); + min = string(bufread + 2, 2); + sec = string(bufread + 4, 2); + msec = string(bufread + 6, 6); break; case 4: - min = string(buf, 2); - sec = string(buf + 2, 2); - msec = string(buf + 4, 6); + min = string(bufread, 2); + sec = string(bufread + 2, 2); + msec = string(bufread + 4, 6); break; case 2: - sec = string(buf, 2); - msec = string(buf + 2, 6); + sec = string(bufread, 2); + msec = string(bufread + 2, 6); break; default: @@ -2686,6 +2723,7 @@ int64_t DataConvert::intToTime(int64_t data) atime.minute = minute; atime.second = s; atime.msecond = ms; + atime.is_neg = isNeg; return *(reinterpret_cast(&atime)); } @@ -2697,11 +2735,20 @@ int64_t DataConvert::stringToTime(const string& data) // -838 <= H <= 838 uint64_t min = 0, sec = 0, msec = 0; int64_t day = -1, hour = 0; + bool isNeg = false; string time, hms, ms; char* end = NULL; + + size_t pos = data.find("-"); + + if (pos != string::npos) + { + isNeg = true; + } + // Day - size_t pos = data.find(" "); + pos = data.find(" "); if (pos != string::npos) { @@ -2762,6 +2809,7 @@ int64_t DataConvert::stringToTime(const string& data) atime.minute = min; atime.second = sec; atime.msecond = msec; + atime.is_neg = isNeg; return *(reinterpret_cast(&atime)); } diff --git a/utils/dataconvert/dataconvert.h b/utils/dataconvert/dataconvert.h index 0992cd843..01e530709 100644 --- a/utils/dataconvert/dataconvert.h +++ b/utils/dataconvert/dataconvert.h @@ -197,14 +197,17 @@ struct Time signed second : 8; signed minute : 8; signed hour : 12; - signed day : 12; + signed day : 11; + signed is_neg : 1; // NULL column value = 0xFFFFFFFFFFFFFFFE Time() : msecond (0xFFFFFE), second (0xFF), minute (0xFF), hour (0xFFF), - day (0xFFF) {} + day (0x7FF), + is_neg (0b1) + {} // Construct a Time from a 64 bit integer InfiniDB time. Time(int64_t val) : @@ -212,11 +215,16 @@ struct Time second((val >> 24) & 0xff), minute((val >> 32) & 0xff), hour((val >> 40) & 0xfff), - day((val >> 52) & 0xfff) + day((val >> 52) & 0x7ff), + is_neg(val >> 63) {} - Time(signed d, signed h, signed min, signed sec, signed msec) : - msecond(msec), second(sec), minute(min), hour(h), day(d) {} + Time(signed d, signed h, signed min, signed sec, signed msec, bool neg) : + msecond(msec), second(sec), minute(min), hour(h), day(d), is_neg(neg) + { + if (h < 0) + is_neg = 0b1; + } int64_t convertToMySQLint() const; void reset(); @@ -229,13 +237,25 @@ void Time::reset() second = 0xFF; minute = 0xFF; hour = 0xFFF; - day = 0xFFF; + is_neg = 0b1; + day = 0x7FF; } inline int64_t Time::convertToMySQLint() const { - return (int64_t) (hour * 10000) + (minute * 100) + second; + if ((hour >= 0) && is_neg) + { + return (int64_t) ((hour * 10000) + (minute * 100) + second) * -1; + } + else if (hour >= 0) + { + return (int64_t) (hour * 10000) + (minute * 100) + second; + } + else + { + return (int64_t) (hour * 10000) - (minute * 100) - second; + } } static uint32_t daysInMonth[13] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; @@ -593,6 +613,12 @@ inline void DataConvert::timeToString( long long timevalue, char* buf, unsigned { msec = (unsigned)((timevalue) & 0xffffff); } + if ((hour >= 0) && (timevalue >> 63)) + { + buf[0] = '-'; + buf++; + buflen--; + } snprintf( buf, buflen, "%02d:%02d:%02d", hour, (unsigned)((timevalue >> 32) & 0xff), @@ -636,13 +662,20 @@ inline void DataConvert::timeToString1( long long timevalue, char* buf, unsigned { // Handle negative correctly int hour = 0; - if ((timevalue >> 40) & 0xf00) + if ((timevalue >> 40) & 0x800) { hour = 0xfffff000; } hour |= ((timevalue >> 40) & 0xfff); + if ((hour >= 0) && (timevalue >> 63)) + { + buf[0] = '-'; + buf++; + buflen--; + } + snprintf( buf, buflen, "%02d%02d%02d", hour, (unsigned)((timevalue >> 32) & 0xff), diff --git a/utils/funcexp/func_bitand.cpp b/utils/funcexp/func_bitand.cpp index 32cb846fe..6906a928a 100644 --- a/utils/funcexp/func_bitand.cpp +++ b/utils/funcexp/func_bitand.cpp @@ -172,6 +172,8 @@ int64_t Func_bitand::getIntVal(Row& row, } hour |= ((time >> 40) & 0xfff); + if ((hour >= 0) && (time >> 63)) + hour*= -1; min = (uint32_t)((time >> 32) & 0xff); sec = (uint32_t)((time >> 24) & 0xff); msec = (uint32_t)(time & 0xffffff); diff --git a/utils/funcexp/func_extract.cpp b/utils/funcexp/func_extract.cpp index 67fc70a4d..c77a23d70 100644 --- a/utils/funcexp/func_extract.cpp +++ b/utils/funcexp/func_extract.cpp @@ -150,6 +150,9 @@ long long timeGet( uint64_t time, IntervalColumn::interval_type unit ) mask = 0xfffffffffffff000; hour = mask | ((time >> 40) & 0xfff); + if ((hour >= 0) && (time >> 63)) + hour*= -1; + // Always positive! day = abs(hour / 24); diff --git a/utils/funcexp/func_greatest.cpp b/utils/funcexp/func_greatest.cpp index 2d7dd15d6..80dbd251f 100644 --- a/utils/funcexp/func_greatest.cpp +++ b/utils/funcexp/func_greatest.cpp @@ -221,7 +221,7 @@ int64_t Func_greatest::getTimeIntVal(rowgroup::Row& row, int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull); int64_t str2 = str1 << 12; - if ( str < str1 ) + if ( str < str2 ) { greatestStr = str1; str = str2; diff --git a/utils/funcexp/func_hour.cpp b/utils/funcexp/func_hour.cpp index 353d0cc4e..631b070c8 100644 --- a/utils/funcexp/func_hour.cpp +++ b/utils/funcexp/func_hour.cpp @@ -128,10 +128,18 @@ int64_t Func_hour::getIntVal(rowgroup::Row& row, if (isTime) { // If negative, mask so it doesn't turn positive + bool isNeg = false; int64_t mask = 0; if ((val >> 40) & 0x800) mask = 0xfffffffffffff000; + + if (!mask && (val >> 63)) + { + isNeg = true; + } val = mask | ((val >> 40) & 0xfff); + if (isNeg) + val*= -1; } else { diff --git a/utils/funcexp/func_least.cpp b/utils/funcexp/func_least.cpp index 2f645af5f..ee5b2afc0 100644 --- a/utils/funcexp/func_least.cpp +++ b/utils/funcexp/func_least.cpp @@ -197,7 +197,7 @@ int64_t Func_least::getTimeIntVal(rowgroup::Row& row, int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull); int64_t str2 = str1 << 12; - if ( str > str1 ) + if ( str > str2 ) { leastStr = str1; str = str2; diff --git a/utils/funcexp/func_second.cpp b/utils/funcexp/func_second.cpp index 678a1fa61..ae12b157c 100644 --- a/utils/funcexp/func_second.cpp +++ b/utils/funcexp/func_second.cpp @@ -111,6 +111,7 @@ int64_t Func_second::getIntVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::TIME: { val = parm[0]->data()->getTimeIntVal(row, isNull); + return (uint32_t)((val >> 24) & 0xff); break; } diff --git a/utils/funcexp/func_time_to_sec.cpp b/utils/funcexp/func_time_to_sec.cpp index b87c2995a..2b8d6e3cc 100644 --- a/utils/funcexp/func_time_to_sec.cpp +++ b/utils/funcexp/func_time_to_sec.cpp @@ -49,12 +49,13 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row, CalpontSystemCatalog::ColType& op_ct) { // assume 256 is enough. assume not allowing incomplete date - uint32_t hour = 0, + int32_t hour = 0, min = 0, sec = 0; bool bIsNegative = false; // Only set to true if CHAR or VARCHAR with a '-' int64_t val = 0; + int64_t mask = 0; dataconvert::Time tval; switch (parm[0]->data()->resultType().colDataType) @@ -64,9 +65,25 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row, case CalpontSystemCatalog::DATETIME: val = parm[0]->data()->getIntVal(row, isNull); - hour = (uint32_t)((val >> 32) & 0x3f); - min = (uint32_t)((val >> 26) & 0x3f); - sec = (uint32_t)((val >> 20) & 0x3f); + hour = (int32_t)((val >> 32) & 0x3f); + min = (int32_t)((val >> 26) & 0x3f); + sec = (int32_t)((val >> 20) & 0x3f); + break; + + case CalpontSystemCatalog::TIME: + val = parm[0]->data()->getTimeIntVal(row, isNull); + // If negative, mask so it doesn't turn positive + if ((val >> 40) & 0x800) + mask = 0xfffffffffffff000; + + bIsNegative = val >> 63; + hour = (int32_t)(mask | ((val >> 40) & 0xfff)); + if ((hour >= 0) && bIsNegative) + hour*= -1; + else + bIsNegative = false; + min = (int32_t)((val >> 32) & 0xff); + sec = (int32_t)((val >> 24) & 0xff); break; case CalpontSystemCatalog::CHAR: @@ -112,9 +129,9 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row, } else { - hour = (uint32_t)((val >> 32) & 0x3f); - min = (uint32_t)((val >> 26) & 0x3f); - sec = (uint32_t)((val >> 20) & 0x3f); + hour = (int32_t)((val >> 32) & 0x3f); + min = (int32_t)((val >> 26) & 0x3f); + sec = (int32_t)((val >> 20) & 0x3f); } break; @@ -131,9 +148,9 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row, } else { - hour = (uint32_t)((val >> 32) & 0x3f); - min = (uint32_t)((val >> 26) & 0x3f); - sec = (uint32_t)((val >> 20) & 0x3f); + hour = (int32_t)((val >> 32) & 0x3f); + min = (int32_t)((val >> 26) & 0x3f); + sec = (int32_t)((val >> 20) & 0x3f); } }