diff options
author | unknown <guilhem@mysql.com> | 2004-07-29 23:25:58 +0200 |
---|---|---|
committer | unknown <guilhem@mysql.com> | 2004-07-29 23:25:58 +0200 |
commit | 88e3aead85b7136fab3d8cfcfa19174c4c2e2662 (patch) | |
tree | 2f01af661dcc90a418853b7a1718fd7a0fe688e1 /sql-common | |
parent | 5ef15478cdbaa65c7d037ce5662117b8ed425dba (diff) | |
download | mariadb-git-88e3aead85b7136fab3d8cfcfa19174c4c2e2662.tar.gz |
WL#1580: --start-datetime, --stop-datetime, --start-position (alias for --position) and --stop-position
options for mysqlbinlog, with a test file.
This enables user to say "recover my database to how it was this morning at 10:30"
(mysqlbinlog "--stop-datetime=2003-07-29 10:30:00").
Using time functions into client/ made me move them out of sql/ into sql-common/.
+ (small) fix for BUG#4507 "mysqlbinlog --read-from-remote-server sometimes
cannot accept 2 binlogs" (that is, on command line).
client/client_priv.h:
new options for mysqlbinlog
client/mysqlbinlog.cc:
WL#1580: --start-datetime, --stop-datetime, --start-position (alias for --position) and --stop-position.
(small) fix for BUG#4507 "mysqlbinlog --read-from-remote-server sometimes
cannot accept 2 binlogs".
include/my_time.h:
importing time functions so that client/ files can use them.
include/mysql_time.h:
importing time types so that client/ files can use them.
sql-common/my_time.c:
importing time functions so that client/ files can use them.
sql/mysql_priv.h:
moving time functions out of sql/ into sql-common/
sql/time.cc:
moving time functions out of sql/ into sql-common/
sql/tztime.h:
moving time functions out of sql/ into sql-common/
Diffstat (limited to 'sql-common')
-rw-r--r-- | sql-common/my_time.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 46c84ac9ba7..24c19be47ba 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -35,6 +35,16 @@ static uchar internal_format_positions[]= static char time_separator=':'; +static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */ +uchar days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; + +/* + Offset of system time zone from UTC in seconds used to speed up + work of my_system_gmt_sec() function. +*/ +static long my_time_zone=0; + + /* Convert a timestamp string to a MYSQL_TIME value. @@ -559,3 +569,148 @@ fractional: } +/* + Prepare offset of system time zone from UTC for my_system_gmt_sec() func. + + SYNOPSIS + init_time() +*/ +void init_time(void) +{ + time_t seconds; + struct tm *l_time,tm_tmp;; + MYSQL_TIME my_time; + bool not_used; + + seconds= (time_t) time((time_t*) 0); + localtime_r(&seconds,&tm_tmp); + l_time= &tm_tmp; + my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */ + my_time.year= (uint) l_time->tm_year+1900; + my_time.month= (uint) l_time->tm_mon+1; + my_time.day= (uint) l_time->tm_mday; + my_time.hour= (uint) l_time->tm_hour; + my_time.minute= (uint) l_time->tm_min; + my_time.second= (uint) l_time->tm_sec; + my_system_gmt_sec(&my_time, &my_time_zone, ¬_used); /* Init my_time_zone */ +} + + + /* Calculate nr of day since year 0 in new date-system (from 1615) */ + +long calc_daynr(uint year,uint month,uint day) +{ + long delsum; + int temp; + DBUG_ENTER("calc_daynr"); + + if (year == 0 && month == 0 && day == 0) + DBUG_RETURN(0); /* Skip errors */ + if (year < 200) + { + if ((year=year+1900) < 1900+YY_PART_YEAR) + year+=100; + } + delsum= (long) (365L * year+ 31*(month-1) +day); + if (month <= 2) + year--; + else + delsum-= (long) (month*4+23)/10; + temp=(int) ((year/100+1)*3)/4; + DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld", + year+(month <= 2),month,day,delsum+year/4-temp)); + DBUG_RETURN(delsum+(int) year/4-temp); +} /* calc_daynr */ + + +/* + Convert time in MYSQL_TIME representation in system time zone to its + my_time_t form (number of seconds in UTC since begginning of Unix Epoch). + + SYNOPSIS + my_system_gmt_sec() + t - time value to be converted + my_timezone - pointer to long where offset of system time zone + from UTC will be stored for caching + in_dst_time_gap - set to true if time falls into spring time-gap + + NOTES + The idea is to cache the time zone offset from UTC (including daylight + saving time) for the next call to make things faster. But currently we + just calculate this offset during startup (by calling init_time() + function) and use it all the time. + Time value provided should be legal time value (e.g. '2003-01-01 25:00:00' + is not allowed). + + RETURN VALUE + Time in UTC seconds since Unix Epoch representation. +*/ +my_time_t +my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap) +{ + uint loop; + time_t tmp; + struct tm *l_time,tm_tmp; + long diff, current_timezone; + + /* + Calculate the gmt time based on current time and timezone + The -1 on the end is to ensure that if have a date that exists twice + (like 2002-10-27 02:00:0 MET), we will find the initial date. + + By doing -3600 we will have to call localtime_r() several times, but + I couldn't come up with a better way to get a repeatable result :( + + We can't use mktime() as it's buggy on many platforms and not thread safe. + */ + tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - + (long) days_at_timestart)*86400L + (long) t->hour*3600L + + (long) (t->minute*60 + t->second)) + (time_t) my_time_zone - + 3600); + current_timezone= my_time_zone; + + localtime_r(&tmp,&tm_tmp); + l_time=&tm_tmp; + for (loop=0; + loop < 2 && + (t->hour != (uint) l_time->tm_hour || + t->minute != (uint) l_time->tm_min); + loop++) + { /* One check should be enough ? */ + /* Get difference in days */ + int days= t->day - l_time->tm_mday; + if (days < -1) + days= 1; // Month has wrapped + else if (days > 1) + days= -1; + diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) + + (long) (60*((int) t->minute - (int) l_time->tm_min))); + current_timezone+= diff+3600; // Compensate for -3600 above + tmp+= (time_t) diff; + localtime_r(&tmp,&tm_tmp); + l_time=&tm_tmp; + } + /* + Fix that if we are in the not existing daylight saving time hour + we move the start of the next real hour + */ + if (loop == 2 && t->hour != (uint) l_time->tm_hour) + { + int days= t->day - l_time->tm_mday; + if (days < -1) + days=1; // Month has wrapped + else if (days > 1) + days= -1; + diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+ + (long) (60*((int) t->minute - (int) l_time->tm_min))); + if (diff == 3600) + tmp+=3600 - t->minute*60 - t->second; // Move to next hour + else if (diff == -3600) + tmp-=t->minute*60 + t->second; // Move to previous hour + + *in_dst_time_gap= 1; + } + *my_timezone= current_timezone; + + return (my_time_t) tmp; +} /* my_system_gmt_sec */ |