1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

MCOL-392 fix negative zero hours

Also fix some functions that were not behaving correctly
This commit is contained in:
Andrew Hutchings
2018-04-30 22:08:10 +01:00
parent 3c090647af
commit dfc351b730
10 changed files with 148 additions and 36 deletions

View File

@ -996,12 +996,12 @@ inline int64_t TreeNode::getDatetimeIntVal()
memcpy(&tt, &fResult.intVal, 8); memcpy(&tt, &fResult.intVal, 8);
// Note, this should probably be current date +/- time // Note, this should probably be current date +/- time
if (tt.hour > 23) if ((tt.hour > 23) && (!tt.is_neg))
{ {
day = tt.hour / 24; day = tt.hour / 24;
tt.hour = tt.hour % 24; tt.hour = tt.hour % 24;
} }
else if (tt.hour < 0) else if ((tt.hour < 0) || (tt.is_neg))
{ {
tt.hour = 0; tt.hour = 0;
} }
@ -1023,7 +1023,7 @@ inline int64_t TreeNode::getTimeIntVal()
dataconvert::DateTime dt; dataconvert::DateTime dt;
memcpy(&dt, &fResult.intVal, 8); 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); memcpy(&fResult.intVal, &tt, 8);
return fResult.intVal; return fResult.intVal;
} }

View File

@ -1005,6 +1005,7 @@ bool mysql_str_to_time( const string& input, Time& output )
output.minute = 59; output.minute = 59;
output.second = 59; output.second = 59;
output.msecond = 999999; output.msecond = 999999;
output.is_neg = 0;
} }
else if (hour < -838) else if (hour < -838)
{ {
@ -1012,6 +1013,7 @@ bool mysql_str_to_time( const string& input, Time& output )
output.minute = 59; output.minute = 59;
output.second = 59; output.second = 59;
output.msecond = 999999; output.msecond = 999999;
output.is_neg = 1;
} }
// If neither of the above match then we return a 0 time // If neither of the above match then we return a 0 time
else else
@ -1025,6 +1027,7 @@ bool mysql_str_to_time( const string& input, Time& output )
output.minute = min; output.minute = min;
output.second = sec; output.second = sec;
output.msecond = usec; output.msecond = usec;
output.is_neg = isNeg;
return true; return true;
} }
@ -1914,12 +1917,18 @@ int64_t DataConvert::convertColumnTime(
inMinute = 0; inMinute = 0;
inSecond = 0; inSecond = 0;
inMicrosecond = 0; inMicrosecond = 0;
bool isNeg = false;
if ( datetimeFormat != CALPONTTIME_ENUM ) if ( datetimeFormat != CALPONTTIME_ENUM )
{ {
status = -1; status = -1;
return value; return value;
} }
if (p[0] == '-')
{
isNeg = true;
}
errno = 0; errno = 0;
p = strtok_r(p, ":.", &savePoint); p = strtok_r(p, ":.", &savePoint);
@ -1981,6 +1990,7 @@ int64_t DataConvert::convertColumnTime(
atime.minute = inMinute; atime.minute = inMinute;
atime.second = inSecond; atime.second = inSecond;
atime.msecond = inMicrosecond; atime.msecond = inMicrosecond;
atime.is_neg = isNeg;
memcpy( &value, &atime, 8); memcpy( &value, &atime, 8);
} }
@ -1994,6 +2004,7 @@ int64_t DataConvert::convertColumnTime(
atime.minute = 59; atime.minute = 59;
atime.second = 59; atime.second = 59;
atime.msecond = 999999; atime.msecond = 999999;
atime.is_neg = false;
memcpy( &value, &atime, 8); memcpy( &value, &atime, 8);
} }
else if (inHour < -838) else if (inHour < -838)
@ -2003,6 +2014,7 @@ int64_t DataConvert::convertColumnTime(
atime.minute = 59; atime.minute = 59;
atime.second = 59; atime.second = 59;
atime.msecond = 999999; atime.msecond = 999999;
atime.is_neg = false;
memcpy( &value, &atime, 8); memcpy( &value, &atime, 8);
} }
// If neither of the above match then we return a 0 time // 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); Time dt(timevalue);
const int TIMETOSTRING_LEN = 19; // (-H)HH:MM:SS.mmmmmm\0 const int TIMETOSTRING_LEN = 19; // (-H)HH:MM:SS.mmmmmm\0
char buf[TIMETOSTRING_LEN]; 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) if (dt.msecond && decimals)
{ {
size_t start = strlen(buf); size_t start = strlen(buf);
@ -2128,7 +2147,9 @@ std::string DataConvert::timeToString1( long long datetimevalue )
const int TIMETOSTRING1_LEN = 14; // HHMMSSmmmmmm\0 const int TIMETOSTRING1_LEN = 14; // HHMMSSmmmmmm\0
char buf[TIMETOSTRING1_LEN]; 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; return buf;
} }
@ -2633,7 +2654,9 @@ int64_t DataConvert::intToDatetime(int64_t data, bool* date)
int64_t DataConvert::intToTime(int64_t data) int64_t DataConvert::intToTime(int64_t data)
{ {
char buf[21] = {0}; char buf[21] = {0};
char* bufread = buf;
Time atime; Time atime;
bool isNeg = false;
if (data == 0) if (data == 0)
{ {
@ -2641,6 +2664,7 @@ int64_t DataConvert::intToTime(int64_t data)
atime.minute = 0; atime.minute = 0;
atime.second = 0; atime.second = 0;
atime.msecond = 0; atime.msecond = 0;
atime.is_neg = 0;
return *(reinterpret_cast<int64_t*>(&atime)); return *(reinterpret_cast<int64_t*>(&atime));
} }
@ -2650,24 +2674,37 @@ int64_t DataConvert::intToTime(int64_t data)
string hour, min, sec, msec; string hour, min, sec, msec;
int64_t h = 0, minute = 0, s = 0, ms = 0; 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: case 6:
hour = string(buf, 2); hour = string(bufread, 2);
min = string(buf + 2, 2); min = string(bufread + 2, 2);
sec = string(buf + 4, 2); sec = string(bufread + 4, 2);
msec = string(buf + 6, 6); msec = string(bufread + 6, 6);
break; break;
case 4: case 4:
min = string(buf, 2); min = string(bufread, 2);
sec = string(buf + 2, 2); sec = string(bufread + 2, 2);
msec = string(buf + 4, 6); msec = string(bufread + 4, 6);
break; break;
case 2: case 2:
sec = string(buf, 2); sec = string(bufread, 2);
msec = string(buf + 2, 6); msec = string(bufread + 2, 6);
break; break;
default: default:
@ -2686,6 +2723,7 @@ int64_t DataConvert::intToTime(int64_t data)
atime.minute = minute; atime.minute = minute;
atime.second = s; atime.second = s;
atime.msecond = ms; atime.msecond = ms;
atime.is_neg = isNeg;
return *(reinterpret_cast<uint64_t*>(&atime)); return *(reinterpret_cast<uint64_t*>(&atime));
} }
@ -2697,11 +2735,20 @@ int64_t DataConvert::stringToTime(const string& data)
// -838 <= H <= 838 // -838 <= H <= 838
uint64_t min = 0, sec = 0, msec = 0; uint64_t min = 0, sec = 0, msec = 0;
int64_t day = -1, hour = 0; int64_t day = -1, hour = 0;
bool isNeg = false;
string time, hms, ms; string time, hms, ms;
char* end = NULL; char* end = NULL;
size_t pos = data.find("-");
if (pos != string::npos)
{
isNeg = true;
}
// Day // Day
size_t pos = data.find(" "); pos = data.find(" ");
if (pos != string::npos) if (pos != string::npos)
{ {
@ -2762,6 +2809,7 @@ int64_t DataConvert::stringToTime(const string& data)
atime.minute = min; atime.minute = min;
atime.second = sec; atime.second = sec;
atime.msecond = msec; atime.msecond = msec;
atime.is_neg = isNeg;
return *(reinterpret_cast<int64_t*>(&atime)); return *(reinterpret_cast<int64_t*>(&atime));
} }

View File

@ -197,14 +197,17 @@ struct Time
signed second : 8; signed second : 8;
signed minute : 8; signed minute : 8;
signed hour : 12; signed hour : 12;
signed day : 12; signed day : 11;
signed is_neg : 1;
// NULL column value = 0xFFFFFFFFFFFFFFFE // NULL column value = 0xFFFFFFFFFFFFFFFE
Time() : msecond (0xFFFFFE), Time() : msecond (0xFFFFFE),
second (0xFF), second (0xFF),
minute (0xFF), minute (0xFF),
hour (0xFFF), hour (0xFFF),
day (0xFFF) {} day (0x7FF),
is_neg (0b1)
{}
// Construct a Time from a 64 bit integer InfiniDB time. // Construct a Time from a 64 bit integer InfiniDB time.
Time(int64_t val) : Time(int64_t val) :
@ -212,11 +215,16 @@ struct Time
second((val >> 24) & 0xff), second((val >> 24) & 0xff),
minute((val >> 32) & 0xff), minute((val >> 32) & 0xff),
hour((val >> 40) & 0xfff), 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) : Time(signed d, signed h, signed min, signed sec, signed msec, bool neg) :
msecond(msec), second(sec), minute(min), hour(h), day(d) {} msecond(msec), second(sec), minute(min), hour(h), day(d), is_neg(neg)
{
if (h < 0)
is_neg = 0b1;
}
int64_t convertToMySQLint() const; int64_t convertToMySQLint() const;
void reset(); void reset();
@ -229,13 +237,25 @@ void Time::reset()
second = 0xFF; second = 0xFF;
minute = 0xFF; minute = 0xFF;
hour = 0xFFF; hour = 0xFFF;
day = 0xFFF; is_neg = 0b1;
day = 0x7FF;
} }
inline inline
int64_t Time::convertToMySQLint() const 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}; 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); msec = (unsigned)((timevalue) & 0xffffff);
} }
if ((hour >= 0) && (timevalue >> 63))
{
buf[0] = '-';
buf++;
buflen--;
}
snprintf( buf, buflen, "%02d:%02d:%02d", snprintf( buf, buflen, "%02d:%02d:%02d",
hour, hour,
(unsigned)((timevalue >> 32) & 0xff), (unsigned)((timevalue >> 32) & 0xff),
@ -636,13 +662,20 @@ inline void DataConvert::timeToString1( long long timevalue, char* buf, unsigned
{ {
// Handle negative correctly // Handle negative correctly
int hour = 0; int hour = 0;
if ((timevalue >> 40) & 0xf00) if ((timevalue >> 40) & 0x800)
{ {
hour = 0xfffff000; hour = 0xfffff000;
} }
hour |= ((timevalue >> 40) & 0xfff); hour |= ((timevalue >> 40) & 0xfff);
if ((hour >= 0) && (timevalue >> 63))
{
buf[0] = '-';
buf++;
buflen--;
}
snprintf( buf, buflen, "%02d%02d%02d", snprintf( buf, buflen, "%02d%02d%02d",
hour, hour,
(unsigned)((timevalue >> 32) & 0xff), (unsigned)((timevalue >> 32) & 0xff),

View File

@ -172,6 +172,8 @@ int64_t Func_bitand::getIntVal(Row& row,
} }
hour |= ((time >> 40) & 0xfff); hour |= ((time >> 40) & 0xfff);
if ((hour >= 0) && (time >> 63))
hour*= -1;
min = (uint32_t)((time >> 32) & 0xff); min = (uint32_t)((time >> 32) & 0xff);
sec = (uint32_t)((time >> 24) & 0xff); sec = (uint32_t)((time >> 24) & 0xff);
msec = (uint32_t)(time & 0xffffff); msec = (uint32_t)(time & 0xffffff);

View File

@ -150,6 +150,9 @@ long long timeGet( uint64_t time, IntervalColumn::interval_type unit )
mask = 0xfffffffffffff000; mask = 0xfffffffffffff000;
hour = mask | ((time >> 40) & 0xfff); hour = mask | ((time >> 40) & 0xfff);
if ((hour >= 0) && (time >> 63))
hour*= -1;
// Always positive! // Always positive!
day = abs(hour / 24); day = abs(hour / 24);

View File

@ -221,7 +221,7 @@ int64_t Func_greatest::getTimeIntVal(rowgroup::Row& row,
int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull); int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull);
int64_t str2 = str1 << 12; int64_t str2 = str1 << 12;
if ( str < str1 ) if ( str < str2 )
{ {
greatestStr = str1; greatestStr = str1;
str = str2; str = str2;

View File

@ -128,10 +128,18 @@ int64_t Func_hour::getIntVal(rowgroup::Row& row,
if (isTime) if (isTime)
{ {
// If negative, mask so it doesn't turn positive // If negative, mask so it doesn't turn positive
bool isNeg = false;
int64_t mask = 0; int64_t mask = 0;
if ((val >> 40) & 0x800) if ((val >> 40) & 0x800)
mask = 0xfffffffffffff000; mask = 0xfffffffffffff000;
if (!mask && (val >> 63))
{
isNeg = true;
}
val = mask | ((val >> 40) & 0xfff); val = mask | ((val >> 40) & 0xfff);
if (isNeg)
val*= -1;
} }
else else
{ {

View File

@ -197,7 +197,7 @@ int64_t Func_least::getTimeIntVal(rowgroup::Row& row,
int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull); int64_t str1 = fp[i]->data()->getTimeIntVal(row, isNull);
int64_t str2 = str1 << 12; int64_t str2 = str1 << 12;
if ( str > str1 ) if ( str > str2 )
{ {
leastStr = str1; leastStr = str1;
str = str2; str = str2;

View File

@ -111,6 +111,7 @@ int64_t Func_second::getIntVal(rowgroup::Row& row,
case execplan::CalpontSystemCatalog::TIME: case execplan::CalpontSystemCatalog::TIME:
{ {
val = parm[0]->data()->getTimeIntVal(row, isNull); val = parm[0]->data()->getTimeIntVal(row, isNull);
return (uint32_t)((val >> 24) & 0xff);
break; break;
} }

View File

@ -49,12 +49,13 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row,
CalpontSystemCatalog::ColType& op_ct) CalpontSystemCatalog::ColType& op_ct)
{ {
// assume 256 is enough. assume not allowing incomplete date // assume 256 is enough. assume not allowing incomplete date
uint32_t hour = 0, int32_t hour = 0,
min = 0, min = 0,
sec = 0; sec = 0;
bool bIsNegative = false; // Only set to true if CHAR or VARCHAR with a '-' bool bIsNegative = false; // Only set to true if CHAR or VARCHAR with a '-'
int64_t val = 0; int64_t val = 0;
int64_t mask = 0;
dataconvert::Time tval; dataconvert::Time tval;
switch (parm[0]->data()->resultType().colDataType) switch (parm[0]->data()->resultType().colDataType)
@ -64,9 +65,25 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row,
case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::DATETIME:
val = parm[0]->data()->getIntVal(row, isNull); val = parm[0]->data()->getIntVal(row, isNull);
hour = (uint32_t)((val >> 32) & 0x3f); hour = (int32_t)((val >> 32) & 0x3f);
min = (uint32_t)((val >> 26) & 0x3f); min = (int32_t)((val >> 26) & 0x3f);
sec = (uint32_t)((val >> 20) & 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; break;
case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::CHAR:
@ -112,9 +129,9 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row,
} }
else else
{ {
hour = (uint32_t)((val >> 32) & 0x3f); hour = (int32_t)((val >> 32) & 0x3f);
min = (uint32_t)((val >> 26) & 0x3f); min = (int32_t)((val >> 26) & 0x3f);
sec = (uint32_t)((val >> 20) & 0x3f); sec = (int32_t)((val >> 20) & 0x3f);
} }
break; break;
@ -131,9 +148,9 @@ int64_t Func_time_to_sec::getIntVal(rowgroup::Row& row,
} }
else else
{ {
hour = (uint32_t)((val >> 32) & 0x3f); hour = (int32_t)((val >> 32) & 0x3f);
min = (uint32_t)((val >> 26) & 0x3f); min = (int32_t)((val >> 26) & 0x3f);
sec = (uint32_t)((val >> 20) & 0x3f); sec = (int32_t)((val >> 20) & 0x3f);
} }
} }