1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-24 22:42:05 +03:00

Merge pull request #4 from LinuxJedi/MCOL-274

Make date handling more in-line with MySQL
This commit is contained in:
dhall-InfiniDB
2016-09-02 09:15:00 -05:00
committed by GitHub
16 changed files with 129 additions and 168 deletions

View File

@ -31,9 +31,6 @@ using namespace std;
#include <boost/algorithm/string/case_conv.hpp>
using namespace boost::algorithm;
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
using namespace execplan;
using namespace ddlpackage;
using namespace logging;

View File

@ -45,9 +45,6 @@ using namespace WriteEngine;
#include <boost/algorithm/string/case_conv.hpp>
using namespace boost::algorithm;
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include "cacheutils.h"
using namespace cacheutils;

View File

@ -28,8 +28,6 @@ using namespace std;
#include <boost/algorithm/string/case_conv.hpp>
using namespace boost::algorithm;
#include <boost/tokenizer.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include <boost/shared_ptr.hpp>
#include "we_messages.h"

View File

@ -33,7 +33,6 @@ using namespace std;
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/algorithm/string/case_conv.hpp>
namespace fs = boost::filesystem;

View File

@ -31,8 +31,6 @@ using namespace std;
#include <boost/algorithm/string/case_conv.hpp>
using namespace boost::algorithm;
#include <boost/tokenizer.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include "calpontsystemcatalog.h"
#include "calpontselectexecutionplan.h"
#include "columnresult.h"
@ -644,24 +642,14 @@ bool mysql_str_to_datetime( const string& input, DateTime& output, bool& isDate
return false;
}
try
{
boost::gregorian::date d(year, mon, day);
// one more check - boost allows year 10000 but we want to limit at 9999
if( year > 9999 )
{
output.reset();
return false;
}
output.year = d.year();
output.month = d.month();
output.day = d.day();
}
catch (...)
if (!isDateValid(day, mon, year))
{
output.reset();
return false;
}
output.year = year;
output.month = mon;
output.day = day;
/**
* Now we need to deal with the time portion.

View File

@ -228,11 +228,17 @@ inline
bool isDateValid ( int day, int month, int year)
{
bool valid = true;
if ( year == 0 && month == 0 && year == 0 )
{
return true;
}
int daycheck = getDaysInMonth( month );
if( month == 2 && isLeapYear( year ) )
// 29 days in February in a leap year
daycheck = 29;
if ( ( year < 1400 ) || ( year > 9999 ) )
if ( ( year < 1000 ) || ( year > 9999 ) )
valid = false;
else if ( month < 1 || month > 12 )
valid = false;

View File

@ -34,7 +34,6 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include "dataconvert.h"
#include "operator.h"
@ -172,39 +171,81 @@ static std::string dayOfMonth[32] =
"31st"
};
static uint8_t days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
// Given a date, calculate the number of days since year 0
// This is a mirror of calc_daynr, at a later date we should use my_time.h
inline uint32_t calc_mysql_daynr( uint32_t year, uint32_t month, uint32_t day )
{
int temp;
int y = year;
long delsum;
if( !dataconvert::isDateValid( day, month, year ) )
return 0;
boost::gregorian::date d( year, month, day );
// this is the number of days between the beginning of the
// Gregorian calendar (November 24, 4714 B.C.) and the starting
// date offset in MySQL which is year 0.
const uint32_t JULIAN_DAY_OFFSET = 1721060;
return d.julian_day() - JULIAN_DAY_OFFSET;
delsum= (long) (365 * y + 31 *((int) month - 1) + (int) day);
if (month <= 2)
y--;
else
delsum-= (long) ((int) month * 4 + 23) / 10;
temp=(int) ((y/100+1)*3)/4;
return delsum+(int) y/4-temp;
}
// used by get_date_from_mysql_daynr() and calc_mysql_week()
inline uint32_t calc_mysql_days_in_year(uint32_t year)
{
return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
366 : 365);
}
// convert from a MySQL day number (offset from year 0) to a date
// This is a mirror of get_date_from_daynr, at a later date we should use sql_time.h
inline void get_date_from_mysql_daynr(long daynr,dataconvert::DateTime & dateTime)
{
// the MySQL day numbers for min/max boost supported dates
const int BOOST_START_OFFSET = 511340; // 1400-01-01
const int BOOST_END_OFFSET = 3652424; // 9999-12-31
uint32_t year, temp, leap_day, day_of_year, days_in_year;
uint8_t *month_pos;
uint32_t ret_year, ret_month, ret_day;
const int MAX_DAY_NUMBER= 3652424;
if( daynr < BOOST_START_OFFSET || daynr > BOOST_END_OFFSET )
{
dateTime.year= dateTime.month = dateTime.day =0;
}
else
{
boost::gregorian::date d(1400,1,1);
d += boost::gregorian::date_duration( daynr - BOOST_START_OFFSET );
dateTime.year = d.year();
dateTime.month = d.month();
dateTime.day = d.day();
}
if (daynr < 366 || daynr > MAX_DAY_NUMBER)
{
dateTime.year= dateTime.month = dateTime.day =0;
return;
}
year= (uint32_t) (daynr*100 / 36525L);
temp=(((year-1)/100+1)*3)/4;
day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
while (day_of_year > (days_in_year= calc_mysql_days_in_year(year)))
{
day_of_year-=days_in_year;
(year)++;
}
leap_day=0;
if (days_in_year == 366)
{
if (day_of_year > 31+28)
{
day_of_year--;
if (day_of_year == 31+28)
leap_day=1; /* Handle leapyears leapday */
}
}
ret_month=1;
for (month_pos= days_in_month ;
day_of_year > (uint32_t) *month_pos ;
day_of_year-= *(month_pos++), (ret_month)++)
;
ret_year=year;
ret_day=day_of_year+leap_day;
dateTime.year = ret_year;
dateTime.month = ret_month;
dateTime.day = ret_day;
}
// Returns the weekday index for a given date:
@ -212,14 +253,15 @@ inline void get_date_from_mysql_daynr(long daynr,dataconvert::DateTime & dateTim
// 0 = Sunday, 1 = Monday, ..., 6 = Saturday
// else:
// 0 = Monday, 1 = Tuesday, ..., 6 = Sunday
// This is a mirror of calc_weekday, at a later date we should use sql_time.h
inline uint32_t calc_mysql_weekday( uint32_t year, uint32_t month, uint32_t day, bool sundayFirst )
{
if( !dataconvert::isDateValid( day, month, year ) )
return 0;
boost::gregorian::date d( year, month, day );
uint32_t ret = d.day_of_week();
return sundayFirst ? ret : (ret + 6) % 7;
uint32_t daynr = calc_mysql_daynr(year, month, day);
return ((int) ((daynr + 5L + (sundayFirst ? 1L : 0L)) % 7));
}
// Flags for calc_mysql_week
@ -250,98 +292,56 @@ inline int16_t convert_mysql_mode_to_modeflags( int16_t mode )
// that need to know the year that the week actually corresponds to -
// see MySQL documentation for how the year returned can be different
// than the year of the input date
//
// This is a mirror of calc_week, at a later date we should use sql_time.h
inline uint32_t calc_mysql_week( uint32_t year, uint32_t month, uint32_t day,
int16_t modeflags,
uint32_t* weekyear = 0 )
{
// need to make sure that the date is valid for boost::gregorian::date
// need to make sure that the date is valid
if( !dataconvert::isDateValid( day, month, year ) )
return 0;
boost::gregorian::date d( year, month, day );
// default this to the year of the input date - will update in the
// scenarios where it is either 1 behind or 1 ahead
if( weekyear )
*weekyear = d.year();
uint32_t days;
uint32_t daynr=calc_mysql_daynr(year,month,day);
uint32_t first_daynr=calc_mysql_daynr(year,1,1);
bool monday_first= modeflags & WEEK_MONDAY_FIRST;
bool week_year= modeflags & WEEK_NO_ZERO;
bool first_weekday= modeflags & WEEK_GT_THREE_DAYS;
// get a date object for the first day of they year in question
boost::gregorian::date yearfirst = boost::gregorian::date(d.year(),1,1);
uint32_t weekday=calc_mysql_weekday(year, 1, 1, !monday_first);
*weekyear=year;
// figure out which day of week Jan-01 is
uint32_t firstweekday = calc_mysql_weekday( d.year(), 1, 1, !( modeflags & WEEK_MONDAY_FIRST ) );
if (month == 1 && day <= 7-weekday)
{
if (!week_year &&
((first_weekday && weekday != 0) ||
(!first_weekday && weekday >= 4)))
return 0;
week_year= 1;
(*weekyear)--;
first_daynr-= (days=calc_mysql_days_in_year(*weekyear));
weekday= (weekday + 53*7- days) % 7;
}
// calculate the offset to the first week starting day
uint32_t firstoffset = firstweekday ? ( 7 - firstweekday ) : 0;
if ((first_weekday && weekday != 0) ||
(!first_weekday && weekday >= 4))
days= daynr - (first_daynr+ (7-weekday));
else
days= daynr - (first_daynr - weekday);
// julian day number for the first day of the first week
uint32_t baseday = yearfirst.julian_day() + firstoffset;
// if using a modeflags where the first week must have >3 days in this year
// we need to check where firstweekday fell. There are 3 cases for Jan-01
// 1) Jan-01 fell on week start - there are obviously at least
// three days this year and baseday already correct
// 2) Jan-01 fell on weekday 1 - 3 - this means that our baseday is
// pointing to next week but there must be at least 3 days this year
// so we need to adjust baseday back by one week
// 3) Jan-01 fell on weekday 4 - 6 - this means there cannot be >3
// days in the week with Jan 01 so our baseday is already correct
if( modeflags & WEEK_GT_THREE_DAYS )
{
if( firstweekday > 0 && firstweekday < 4 )
{
baseday = baseday - 7;
}
}
uint32_t weeknum = 0;
if( d.julian_day() < baseday && ( modeflags & WEEK_NO_ZERO ) )
{
// this is somewhat of a pain - since we aren't using a 0 week, the date
// is actually going to be in the last week of last year and we need to
// figure out which number that is. This code is identical to above
// except we are compuing for last year instead of current year.
boost::gregorian::date lastyearfirst = boost::gregorian::date(d.year()-1,1,1);
firstweekday = calc_mysql_weekday( d.year()-1, 1, 1, !( modeflags & WEEK_MONDAY_FIRST ) );
firstoffset = firstweekday ? ( 7 - firstweekday ) : 0;
baseday = lastyearfirst.julian_day() + firstoffset;
// same logic as above
if( modeflags & WEEK_GT_THREE_DAYS )
{
if( firstweekday > 0 && firstweekday < 4 )
{
baseday = baseday - 7;
}
}
weeknum = (d.julian_day() - baseday)/ 7 + 1;
if( weekyear )
*weekyear = d.year() - 1;
}
else
{
weeknum = (d.julian_day() >= baseday) ? (d.julian_day() - baseday)/ 7 + 1 : 0;
if( ( modeflags & WEEK_GT_THREE_DAYS ) &&
( modeflags & WEEK_NO_ZERO ) && weeknum > 52 )
{
// if this happens we aren't sure whether the week will be 53 or 1.
// to get 53, we know this has to be a December date and can subtract
// our date from 32 to figure out how many days of this week
uint32_t daysthisyear = 32 - d.day();
uint32_t firstweekday = calc_mysql_weekday( d.year(), d.month(), d.day(), !( modeflags & 0x1 ) );
// to be 1st week of next year there must be > 3 days of next year
if( ( firstweekday + daysthisyear ) < 4 )
{
weeknum = 1;
if( weekyear )
*weekyear = d.year() + 1;
}
}
}
return weeknum;
if (week_year && days >= 52*7)
{
weekday= (weekday + calc_mysql_days_in_year(*weekyear)) % 7;
if ((!first_weekday && weekday < 4) ||
(first_weekday && weekday == 0))
{
(*weekyear)++;
return 1;
}
}
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)

View File

@ -67,8 +67,7 @@ public:
if( dayOfWeek < 0 || !dataconvert::isDateValid( 1, 1, dateTime.year ) )
return returnError( dateTime );
boost::gregorian::date yearfirst( dateTime.year, 1, 1 );
uint32_t yearfirst = helpers::calc_mysql_daynr(dateTime.year, 1, 1);
// figure out which day of week Jan-01 is
uint32_t firstweekday = helpers::calc_mysql_weekday( dateTime.year, 1, 1, sundayFirst );
@ -76,10 +75,8 @@ public:
uint32_t firstoffset = firstweekday ? ( 7 - firstweekday ) : 0;
firstoffset += ( ( weekOfYear - 1) * 7 ) + dayOfWeek - ( sundayFirst ? 0 : 1 );
yearfirst += boost::gregorian::date_duration( firstoffset );
dateTime.year = yearfirst.year();
dateTime.month = yearfirst.month();
dateTime.day = yearfirst.day();
yearfirst += firstoffset;
helpers::get_date_from_mysql_daynr(yearfirst, dateTime);
}
if( !dataconvert::isDateTimeValid( dateTime.hour, dateTime.minute, dateTime.second, dateTime.msecond ) )

View File

@ -25,8 +25,6 @@ using namespace messageqcpp;
#include "resourcemanager.h"
#include "ddlpkg.h"
#include "ddlpackageprocessor.h"
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include "dataconvert.h"
using namespace dataconvert;
using namespace ddlpackage;

View File

@ -34,7 +34,6 @@
#define EXPORT
#endif
#include <boost/date_time/gregorian/gregorian.hpp>
#include "dataconvert.h"
namespace WriteEngine

View File

@ -25,8 +25,6 @@ using namespace messageqcpp;
#include "resourcemanager.h"
#include "../../dbcon/dmlpackage/dmlpkg.h"
#include "ddlpackageprocessor.h"
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include "dataconvert.h"
using namespace dataconvert;
using namespace dmlpackage;

View File

@ -34,7 +34,6 @@
#define EXPORT
#endif
#include <boost/date_time/gregorian/gregorian.hpp>
#include "dataconvert.h"
namespace WriteEngine

View File

@ -34,8 +34,7 @@ using namespace messageqcpp;
#include "we_ddlcommandproc.h"
#include "ddlpkg.h"
using namespace ddlpackage;
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include <ctime>
#include "dataconvert.h"
using namespace dataconvert;
//#include "we_brm.h"
@ -188,25 +187,15 @@ uint8_t WE_DDLCommandProc::writeSystable(ByteStream& bs, std::string &err)
}
else if (CREATEDATE_COL == column.tableColName.column)
{
date d(day_clock::universal_day());
std::string date = to_iso_string(d);
Date aDay;
int intvalue;
std::string s = date.substr(0, 4);
if (from_string<int>(intvalue, s, std::dec))
{
aDay.year = intvalue;
}
s = date.substr(4, 2);
if (from_string<int>(intvalue, s, std::dec))
{
aDay.month = intvalue;
}
s = date.substr(6, 2);
if (from_string<int>(intvalue, s, std::dec))
{
aDay.day = intvalue;
}
time_t t;
struct tm tmp;
Date aDay;
t = time(NULL);
gmtime_r(&t, &tmp);
aDay.year = tmp.tm_year;
aDay.month = tmp.tm_mon+1;
aDay.day = tmp.tm_mday;
colTuple.data = *(reinterpret_cast<int *> (&aDay));

View File

@ -28,7 +28,6 @@
#include "dbrm.h"
#include "we_message_handlers.h"
#include "liboamcpp.h"
#include <boost/date_time/gregorian/gregorian.hpp>
#include "dataconvert.h"
#include "writeengine.h"

View File

@ -30,8 +30,6 @@ using namespace messageqcpp;
using namespace dmlpackage;
#include "dmlpackageprocessor.h"
using namespace dmlpackageprocessor;
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;
#include "dataconvert.h"
using namespace dataconvert;
#include "calpontsystemcatalog.h"

View File

@ -33,7 +33,6 @@
#include "calpontsystemcatalog.h"
#include "insertdmlpackage.h"
#include "liboamcpp.h"
#include <boost/date_time/gregorian/gregorian.hpp>
#include "dataconvert.h"
#include "writeengine.h"
#include "we_convertor.h"