1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-24 18:27:02 +03:00
Leonid Fedorov 2e1394149b
MCOL-5464: Fixes of bugs from ASAN warnings, part one (#2792)
* Fixes of bugs from ASAN warnings, part one

* MQC as static library, with nifty counter for global map and mutex

* Switch clang to 16

* link messageqcpp to execplan
2023-04-04 02:33:23 +03:00

842 lines
16 KiB
C++

/* Copyright (C) 2014 InfiniDB, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of
the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/****************************************************************************
* $Id: func_date_add.cpp 3905 2013-06-18 12:27:32Z bwilkinson $
*
*
****************************************************************************/
#include <cstdlib>
#include <string>
using namespace std;
#include "boost/assign.hpp"
using namespace boost::assign;
#include "functor_dtm.h"
#include "functioncolumn.h"
#include "intervalcolumn.h"
#include "constantcolumn.h"
#include "rowgroup.h"
using namespace execplan;
#include "dataconvert.h"
using namespace dataconvert;
#include "funchelpers.h"
namespace funcexp
{
namespace helpers
{
uint64_t dateAdd(uint64_t time, const string& expr, IntervalColumn::interval_type unit, bool dateType,
OpType funcType)
{
int array[10];
int64_t array2[10];
int month_length[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int32_t year = 0, month = 0, day = 0, hour = 0, monthSave = 0;
int64_t min = 0, sec = 0, msec = 0;
int32_t yearAdd = 0, monthAdd = 0, dayAdd = 0, hourAdd = 0;
int64_t minAdd = 0, secAdd = 0, msecAdd = 0;
if (dateType)
{
year = (uint32_t)((time >> 16) & 0xffff);
month = (uint32_t)((time >> 12) & 0xf);
day = (uint32_t)((time >> 6) & 0x3f);
}
else
{
year = (uint32_t)((time >> 48) & 0xffff);
month = (uint32_t)((time >> 44) & 0xf);
day = (uint32_t)((time >> 38) & 0x3f);
hour = (uint32_t)((time >> 32) & 0x3f);
min = (uint32_t)((time >> 26) & 0x3f);
sec = (uint32_t)((time >> 20) & 0x3f);
msec = (uint32_t)((time & 0xfffff));
}
monthSave = month;
int index = -1;
switch (unit)
{
case IntervalColumn::INTERVAL_MINUTE:
case IntervalColumn::INTERVAL_SECOND:
case IntervalColumn::INTERVAL_MICROSECOND: index = getNumbers(expr, array2, funcType); break;
default: index = getNumbers(expr, array, funcType); break;
};
if (index <= 0)
throw runtime_error("expression type is not supported");
switch (unit)
{
case IntervalColumn::INTERVAL_YEAR:
{
yearAdd = array[0];
break;
}
case IntervalColumn::INTERVAL_QUARTER:
{
monthAdd = array[0] * 3;
break;
}
case IntervalColumn::INTERVAL_MONTH:
{
monthAdd = array[0];
break;
}
case IntervalColumn::INTERVAL_WEEK:
{
dayAdd = array[0] * 7;
break;
}
case IntervalColumn::INTERVAL_DAY:
{
dayAdd = array[0];
break;
}
case IntervalColumn::INTERVAL_HOUR:
{
hourAdd = array[0];
break;
}
case IntervalColumn::INTERVAL_MINUTE:
{
minAdd = array2[0];
break;
}
case IntervalColumn::INTERVAL_SECOND:
{
secAdd = array2[0];
break;
}
case IntervalColumn::INTERVAL_MICROSECOND:
{
msecAdd = array2[0];
break;
}
case IntervalColumn::INTERVAL_YEAR_MONTH:
{
if (index > 2)
{
return 0;
}
if (index == 1)
monthAdd = array[0];
else
{
yearAdd = array[0];
monthAdd = array[1];
}
break;
}
case IntervalColumn::INTERVAL_DAY_HOUR:
{
if (index > 2)
{
return 0;
}
if (index == 1)
hourAdd = array[0];
else
{
dayAdd = array[0];
hourAdd = array[1];
}
break;
}
case IntervalColumn::INTERVAL_DAY_MINUTE:
{
if (index > 3)
{
return 0;
}
if (index == 1)
minAdd = array[0];
else
{
if (index == 2)
{
hourAdd = array[0];
minAdd = array[1];
}
else
{
dayAdd = array[0];
hourAdd = array[1];
minAdd = array[2];
}
}
break;
}
case IntervalColumn::INTERVAL_DAY_SECOND:
{
if (index > 4)
{
return 0;
}
if (index == 1)
secAdd = array[0];
else
{
if (index == 2)
{
minAdd = array[0];
secAdd = array[1];
}
else
{
if (index == 3)
{
hourAdd = array[0];
minAdd = array[1];
secAdd = array[2];
}
else
{
dayAdd = array[0];
hourAdd = array[1];
minAdd = array[2];
secAdd = array[3];
}
}
}
break;
}
case IntervalColumn::INTERVAL_HOUR_MINUTE:
{
if (index > 2)
{
return 0;
}
if (index == 1)
minAdd = array[0];
else
{
hourAdd = array[0];
minAdd = array[1];
}
break;
}
case IntervalColumn::INTERVAL_HOUR_SECOND:
{
if (index > 3)
{
return 0;
}
if (index == 1)
secAdd = array[0];
else
{
if (index == 2)
{
minAdd = array[0];
secAdd = array[1];
}
else
{
hourAdd = array[0];
minAdd = array[1];
secAdd = array[2];
}
}
break;
}
case IntervalColumn::INTERVAL_MINUTE_SECOND:
{
if (index > 2)
{
return 0;
}
if (index == 1)
secAdd = array[0];
else
{
minAdd = array[0];
secAdd = array[1];
}
break;
}
case IntervalColumn::INTERVAL_DAY_MICROSECOND:
{
if (index > 5)
{
return 0;
}
if (index == 1)
msecAdd = array[0];
else
{
if (index == 2)
{
secAdd = array[0];
msecAdd = array[1];
}
else
{
if (index == 3)
{
minAdd = array[0];
secAdd = array[1];
msecAdd = array[2];
}
else
{
if (index == 4)
{
hourAdd = array[0];
minAdd = array[1];
secAdd = array[2];
msecAdd = array[3];
}
else
{
dayAdd = array[0];
hourAdd = array[1];
minAdd = array[2];
secAdd = array[3];
msecAdd = array[4];
}
}
}
}
break;
}
case IntervalColumn::INTERVAL_HOUR_MICROSECOND:
{
if (index > 4)
{
return 0;
}
if (index == 1)
msecAdd = array[0];
else
{
if (index == 2)
{
secAdd = array[0];
msecAdd = array[1];
}
else
{
if (index == 3)
{
minAdd = array[0];
secAdd = array[1];
msecAdd = array[2];
}
else
{
hourAdd = array[0];
minAdd = array[1];
secAdd = array[2];
msecAdd = array[3];
}
}
}
break;
}
case IntervalColumn::INTERVAL_MINUTE_MICROSECOND:
{
if (index > 3)
{
return 0;
}
if (index == 1)
msecAdd = array[0];
else
{
if (index == 2)
{
secAdd = array[0];
msecAdd = array[1];
}
else
{
minAdd = array[0];
secAdd = array[1];
msecAdd = array[2];
}
}
break;
}
case IntervalColumn::INTERVAL_SECOND_MICROSECOND:
{
if (index > 2)
{
return 0;
}
if (index == 1)
msecAdd = array[0];
else
{
secAdd = array[0];
msecAdd = array[1];
}
break;
}
default:
// should be impossible to get here since we checked the presence
// in the map, but just to be safe...
throw runtime_error("unit type is not supported");
};
// calulate new date
year += yearAdd;
month += monthAdd;
day += dayAdd;
hour += hourAdd;
min += minAdd;
sec += secAdd;
msec += msecAdd;
if (msec > 999999)
{
int64_t secs = msec / 1000000;
sec += secs;
msec = msec - (secs * 1000000);
}
if (msec < 0)
{
int64_t secs = 1 + (-msec / 1000000);
sec -= secs;
msec = msec + (secs * 1000000);
}
if (sec > 59)
{
int64_t mins = sec / 60;
min += mins;
sec = sec - (mins * 60);
}
if (sec < 0)
{
int64_t mins = 0;
if ((sec + (-sec / 60) * 60) == 0 && sec != 0)
mins = (-sec / 60);
else
mins = 1 + (-sec / 60);
min -= mins;
sec = sec + (mins * 60);
if (sec >= 60)
sec = 0;
}
if (min > 59)
{
int hours = min / 60;
hour += hours;
min = min - (hours * 60);
}
if (min < 0)
{
int hours = 0;
if ((min + (-min / 60) * 60) == 0 && min != 0)
hours = (-min / 60);
else
hours = 1 + (-min / 60);
hour -= hours;
min = min + (hours * 60);
if (min >= 60)
min = 0;
}
if (hour > 23)
{
int days = hour / 24;
day += days;
hour = hour - (days * 24);
}
if (hour < 0)
{
int days = 0;
if ((hour + (-hour / 24) * 24) == 0 && hour != 0)
days = (-hour / 24);
else
days = 1 + (-hour / 24);
day -= days;
hour = hour + (days * 24);
if (hour >= 24)
hour = 0;
}
int tmpYear = year;
if (isLeapYear(tmpYear))
month_length[2] = 29;
else
month_length[2] = 28;
if (day > 0)
{
while (true)
{
int years = (monthSave - 1) / 12;
// tmpYear += years;
if (isLeapYear(tmpYear))
month_length[2] = 29;
else
month_length[2] = 28;
int tmpMonth = monthSave - (years * 12);
if (day <= month_length[tmpMonth])
break;
month++;
day = day - month_length[tmpMonth];
monthSave++;
if (monthSave > 12)
{
monthSave = 1;
tmpYear++;
}
}
}
else
{
while (true)
{
if (day > 0)
break;
if (-day < month_length[monthSave])
{
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
}
month--;
monthSave--;
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
}
if (monthSave == 2)
{
// if ( dataconvert::DataConvert::isLeapYear(year) )
if (isLeapYear(tmpYear))
month_length[2] = 29;
}
if (day < 1)
day = month_length[monthSave] + day;
// BUG 5448 - changed from '==' to '<='
if (day <= 0)
{
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
}
month--;
monthSave--;
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
}
if (monthSave == 2)
{
// if ( dataconvert::DataConvert::isLeapYear(year) )
if (isLeapYear(tmpYear))
month_length[2] = 29;
}
day = day + month_length[monthSave];
}
break;
}
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
if (isLeapYear(tmpYear))
month_length[2] = 29;
else
month_length[2] = 28;
}
month--;
monthSave--;
if (monthSave == 0)
{
monthSave = 12;
tmpYear--;
if (isLeapYear(tmpYear))
month_length[2] = 29;
else
month_length[2] = 28;
}
day = day + month_length[monthSave];
}
}
if (month > 12)
{
int years = (month - 1) / 12;
year += years;
month = month - (years * 12);
}
if (month < 1)
{
int years = 1 + ((-month) / 12);
year -= years;
month = month + (years * 12);
}
if (isLeapYear(year))
month_length[2] = 29;
else
month_length[2] = 28;
if (day > month_length[month])
day = month_length[month];
if (year < 1000 || year > 9999)
{
return 0;
}
uint64_t value;
dataconvert::DateTime aDatetime;
aDatetime.year = year;
aDatetime.month = month;
aDatetime.day = day;
aDatetime.hour = hour;
aDatetime.minute = min;
aDatetime.second = sec;
aDatetime.msecond = msec;
value = *(reinterpret_cast<uint64_t*>(&aDatetime));
return value;
}
} // namespace helpers
CalpontSystemCatalog::ColType Func_date_add::operationType(FunctionParm& fp,
CalpontSystemCatalog::ColType& resultType)
{
resultType.colDataType = CalpontSystemCatalog::DATETIME;
resultType.colWidth = 8;
return resultType;
}
int64_t Func_date_add::getIntVal(rowgroup::Row& row, FunctionParm& parm, bool& isNull,
CalpontSystemCatalog::ColType& ct)
{
int64_t val = 0;
bool dateType = false;
switch (parm[0]->data()->resultType().colDataType)
{
case execplan::CalpontSystemCatalog::BIGINT:
case execplan::CalpontSystemCatalog::INT:
case execplan::CalpontSystemCatalog::MEDINT:
case execplan::CalpontSystemCatalog::TINYINT:
case execplan::CalpontSystemCatalog::SMALLINT:
{
val = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull));
break;
}
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
{
if (parm[0]->data()->resultType().scale == 0)
val = dataconvert::DataConvert::intToDatetime(parm[0]->data()->getIntVal(row, isNull));
else
isNull = true;
break;
}
case execplan::CalpontSystemCatalog::VARCHAR:
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::TEXT:
{
val = dataconvert::DataConvert::stringToDatetime(parm[0]->data()->getStrVal(row, isNull).safeString(""));
break;
}
case execplan::CalpontSystemCatalog::DATE:
{
val = parm[0]->data()->getDateIntVal(row, isNull);
dateType = true;
break;
}
case execplan::CalpontSystemCatalog::DATETIME:
{
val = parm[0]->data()->getDatetimeIntVal(row, isNull);
break;
}
case execplan::CalpontSystemCatalog::TIMESTAMP:
{
TimeStamp timestamp(parm[0]->data()->getTimestampIntVal(row, isNull));
int64_t seconds = timestamp.second;
MySQLTime m_time;
gmtSecToMySQLTime(seconds, m_time, ct.getTimeZone());
DateTime dt;
dt.year = m_time.year;
dt.month = m_time.month;
dt.day = m_time.day;
dt.hour = m_time.hour;
dt.minute = m_time.minute;
dt.second = m_time.second;
dt.msecond = timestamp.msecond;
val = *(reinterpret_cast<int64_t*>(&dt));
break;
}
default:
{
isNull = true;
}
}
if (isNull || val == -1)
{
isNull = true;
return 0;
}
IntervalColumn::interval_type unit =
static_cast<IntervalColumn::interval_type>(parm[2]->data()->getIntVal(row, isNull));
OpType funcType = OP_ADD;
ConstantColumn* constCol = dynamic_cast<ConstantColumn*>(parm[3]->data());
execplan::CalpontSystemCatalog::ColType ct3 = parm[3]->data()->resultType();
if ((ct3.colDataType == execplan::CalpontSystemCatalog::CHAR ||
ct3.colDataType == execplan::CalpontSystemCatalog::TEXT ||
ct3.colDataType == execplan::CalpontSystemCatalog::VARCHAR) &&
constCol != NULL && constCol->constval().safeString().compare("SUB") == 0)
funcType = OP_SUB;
else
funcType = static_cast<OpType>(parm[3]->data()->getIntVal(row, isNull));
uint64_t value = helpers::dateAdd(val, parm[1]->data()->getStrVal(row, isNull).safeString(""), unit, dateType, funcType);
if (value == 0)
isNull = true;
// if (dateType)
// value = (((value >> 32) & 0xFFFFFFC0) | 0x3E);
return value;
}
string Func_date_add::getStrVal(rowgroup::Row& row, FunctionParm& parm, bool& isNull,
CalpontSystemCatalog::ColType& ct)
{
return dataconvert::DataConvert::datetimeToString(getIntVal(row, parm, isNull, ct));
}
} // namespace funcexp