From e84f7939ecdebf760f345e61da0ea267311f0db6 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Oct 2005 15:32:31 -0700 Subject: [PATCH 1/5] Fix calculation of TIMESTAMPDIFF() of months and years. (Bug #13534) mysql-test/r/func_time.result: Add new results mysql-test/t/func_time.test: Add new regression test sql/item_timefunc.cc: Fix calculation of years and months in TIMESTAMPDIFF(). --- mysql-test/r/func_time.result | 51 ++++++++++++++++++++++++++++ mysql-test/t/func_time.test | 24 +++++++++++++ sql/item_timefunc.cc | 63 ++++++++++++----------------------- 3 files changed, 96 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 9275a893309..64dafa132b4 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -760,3 +760,54 @@ call t_sysdate(); @a != @b 1 drop procedure t_sysdate; +select timestampdiff(month,'2004-09-11','2004-09-11'); +timestampdiff(month,'2004-09-11','2004-09-11') +0 +select timestampdiff(month,'2004-09-11','2005-09-11'); +timestampdiff(month,'2004-09-11','2005-09-11') +12 +select timestampdiff(month,'2004-09-11','2006-09-11'); +timestampdiff(month,'2004-09-11','2006-09-11') +24 +select timestampdiff(month,'2004-09-11','2007-09-11'); +timestampdiff(month,'2004-09-11','2007-09-11') +36 +select timestampdiff(month,'2005-09-11','2004-09-11'); +timestampdiff(month,'2005-09-11','2004-09-11') +-12 +select timestampdiff(month,'2005-09-11','2003-09-11'); +timestampdiff(month,'2005-09-11','2003-09-11') +-24 +select timestampdiff(month,'2004-02-28','2005-02-28'); +timestampdiff(month,'2004-02-28','2005-02-28') +12 +select timestampdiff(month,'2004-02-29','2005-02-28'); +timestampdiff(month,'2004-02-29','2005-02-28') +11 +select timestampdiff(month,'2004-02-28','2005-02-28'); +timestampdiff(month,'2004-02-28','2005-02-28') +12 +select timestampdiff(month,'2004-03-29','2005-03-28'); +timestampdiff(month,'2004-03-29','2005-03-28') +11 +select timestampdiff(month,'2003-02-28','2004-02-29'); +timestampdiff(month,'2003-02-28','2004-02-29') +12 +select timestampdiff(month,'2003-02-28','2005-02-28'); +timestampdiff(month,'2003-02-28','2005-02-28') +24 +select timestampdiff(month,'1999-09-11','2001-10-10'); +timestampdiff(month,'1999-09-11','2001-10-10') +24 +select timestampdiff(month,'1999-09-11','2001-9-11'); +timestampdiff(month,'1999-09-11','2001-9-11') +24 +select timestampdiff(year,'1999-09-11','2001-9-11'); +timestampdiff(year,'1999-09-11','2001-9-11') +2 +select timestampdiff(year,'2004-02-28','2005-02-28'); +timestampdiff(year,'2004-02-28','2005-02-28') +1 +select timestampdiff(year,'2004-02-29','2005-02-28'); +timestampdiff(year,'2004-02-29','2005-02-28') +0 diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 3dd7f7276fb..3a2eea59bed 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -404,4 +404,28 @@ delimiter ;// call t_sysdate(); drop procedure t_sysdate; +# +# Bug #13534: timestampdiff() returned incorrect results across leap years +# +select timestampdiff(month,'2004-09-11','2004-09-11'); +select timestampdiff(month,'2004-09-11','2005-09-11'); +select timestampdiff(month,'2004-09-11','2006-09-11'); +select timestampdiff(month,'2004-09-11','2007-09-11'); +select timestampdiff(month,'2005-09-11','2004-09-11'); +select timestampdiff(month,'2005-09-11','2003-09-11'); + +select timestampdiff(month,'2004-02-28','2005-02-28'); +select timestampdiff(month,'2004-02-29','2005-02-28'); +select timestampdiff(month,'2004-02-28','2005-02-28'); +select timestampdiff(month,'2004-03-29','2005-03-28'); +select timestampdiff(month,'2003-02-28','2004-02-29'); +select timestampdiff(month,'2003-02-28','2005-02-28'); + +select timestampdiff(month,'1999-09-11','2001-10-10'); +select timestampdiff(month,'1999-09-11','2001-9-11'); + +select timestampdiff(year,'1999-09-11','2001-9-11'); +select timestampdiff(year,'2004-02-28','2005-02-28'); +select timestampdiff(year,'2004-02-29','2005-02-28'); + # End of 5.0 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 7f94c19647e..459b5a22cb1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2723,16 +2723,16 @@ longlong Item_func_timestamp_diff::val_int() int_type == INTERVAL_QUARTER || int_type == INTERVAL_MONTH) { - uint year; - uint year_beg, year_end, month_beg, month_end; - uint diff_days= (uint) (seconds/86400L); - uint diff_years= 0; + uint year_beg, year_end, month_beg, month_end, day_beg, day_end; + uint years= 0; if (neg == -1) { year_beg= ltime2.year; year_end= ltime1.year; month_beg= ltime2.month; month_end= ltime1.month; + day_beg= ltime2.day; + day_end= ltime1.day; } else { @@ -2740,53 +2740,32 @@ longlong Item_func_timestamp_diff::val_int() year_end= ltime2.year; month_beg= ltime1.month; month_end= ltime2.month; - } - /* calc years*/ - for (year= year_beg;year < year_end; year++) - { - uint days=calc_days_in_year(year); - if (days > diff_days) - break; - diff_days-= days; - diff_years++; + day_beg= ltime1.day; + day_end= ltime2.day; } - /* calc months; Current year is in the 'year' variable */ - month_beg--; /* Change months to be 0-11 for easier calculation */ - month_end--; + /* calc years */ + years= year_end - year_beg; + if (month_end < month_beg || (month_end == month_beg && day_end < day_beg)) + years-= 1; - months= 12*diff_years; - while (month_beg != month_end) - { - uint m_days= (uint) days_in_month[month_beg]; - if (month_beg == 1) - { - /* This is only calculated once so there is no reason to cache it*/ - uint leap= (uint) ((year & 3) == 0 && (year%100 || - (year%400 == 0 && year))); - m_days+= leap; - } - if (m_days > diff_days) - break; - diff_days-= m_days; - months++; - if (month_beg++ == 11) /* if we wrap to next year */ - { - month_beg= 0; - year++; - } - } - if (neg == -1) - months= -months; + /* calc months */ + months= 12*years; + if (month_end < month_beg || (month_end == month_beg && day_end < day_beg)) + months+= 12 - (month_beg - month_end); + else + months+= (month_end - month_beg); + if (day_end < day_beg) + months-= 1; } switch (int_type) { case INTERVAL_YEAR: - return months/12; + return months/12*neg; case INTERVAL_QUARTER: - return months/3; + return months/3*neg; case INTERVAL_MONTH: - return months; + return months*neg; case INTERVAL_WEEK: return seconds/86400L/7L*neg; case INTERVAL_DAY: From 9b20b6c955b3c4c571f1c2339fc7d5161c791004 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Oct 2005 20:08:56 +0400 Subject: [PATCH 2/5] Fixes bug #14137. Converts charsets_dir path to underlying system representation. sql/mysqld.cc: Added code to convert charsets_dir path to system representation. --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e51eb481767..a0a5864ebee 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7155,6 +7155,7 @@ static void fix_paths(void) CHARSET_DIR, NullS); } (void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff); + convert_dirname(mysql_charsets_dir,mysql_charsets_dir,NullS); charsets_dir=mysql_charsets_dir; if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) From e17b176e9b9a2589a54e972bdede1138937317cc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Oct 2005 02:27:55 +0200 Subject: [PATCH 3/5] Makefile.am: Option to set environment variable MTR_BUILD_THREAD to a small number, from what mysql-test-run calculate port numbers that will not conflict with other runs with different thread num Makefile.am: Option to set environment variable MTR_BUILD_THREAD to a small number, from what mysql-test-run calculate port numbers that will not conflict with other runs with different thread num --- Makefile.am | 17 ++++++++--------- mysql-test/mysql-test-run.sh | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Makefile.am b/Makefile.am index be2d34f8db8..35c5a51caf4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,15 +85,14 @@ tags: support-files/build-tags .PHONY: init-db bin-dist -# Test installation. Ports are configurable from the environment. - -MYSQL_TEST_MANAGER_PORT = 9305 -MYSQL_TEST_MASTER_PORT = 9306 -MYSQL_TEST_SLAVE_PORT = 9308 +# Target 'test' will run the regression test suite using the built server. +# +# If you are running in a shared environment, users can avoid clashing +# port numbers by setting individual small numbers 1-100 to the +# environment variable MTR_BUILD_THREAD. The script "mysql-test-run" +# will then calculate the various port numbers it needs from this, +# making sure each user use different ports. test: cd mysql-test ; \ - ./mysql-test-run \ - --manager-port=$(MYSQL_TEST_MANAGER_PORT) \ - --master_port=$(MYSQL_TEST_MASTER_PORT) \ - --slave_port=$(MYSQL_TEST_SLAVE_PORT) + ./mysql-test-run diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index b760309bb5b..9a2c4345bae 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -201,6 +201,23 @@ MYSQL_MANAGER_PORT=9305 # needs to be out of the way of slaves MYSQL_MANAGER_PW_FILE=$MYSQL_TEST_DIR/var/tmp/manager.pwd MYSQL_MANAGER_LOG=$MYSQL_TEST_DIR/var/log/manager.log MYSQL_MANAGER_USER=root + +# +# To make it easier for different devs to work on the same host, +# an environment variable can be used to control all ports. A small +# number is to be used, 0 - 16 or similar. +# +if [ -n "$MTR_BUILD_THREAD" ] ; then + MASTER_MYPORT=`expr $MTR_BUILD_THREAD '*' 40 + 8120` + SLAVE_MYPORT=`expr $MASTER_MYPORT + 16` + MYSQL_MANAGER_PORT=`expr $MASTER_MYPORT + 2` + + echo "Using MTR_BUILD_THREAD = $MTR_BUILD_THREAD" + echo "Using MASTER_MYPORT = $MASTER_MYPORT" + echo "Using MYSQL_MANAGER_PORT = $MYSQL_MANAGER_PORT" + echo "Using SLAVE_MYPORT = $SLAVE_MYPORT" +fi + NO_SLAVE=0 USER_TEST= FAILED_CASES= From c9f5c069f9f3cfbe9637d69c1a41233feb401c03 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Oct 2005 23:51:05 -0500 Subject: [PATCH 4/5] changed define from EXTERN_C to EXTERNC so it doesn't conflict with another macro defined in the Windows header files. --- include/my_pthread.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/my_pthread.h b/include/my_pthread.h index 3d9056541d7..ee2c801ff6e 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -25,10 +25,10 @@ #endif #ifdef __cplusplus -#define EXTERN_C extern "C" +#define EXTERNC extern "C" extern "C" { #else -#define EXTERN_C +#define EXTERNC #endif /* __cplusplus */ #if defined(__WIN__) || defined(OS2) @@ -80,10 +80,10 @@ struct timespec { /* For pthread_cond_timedwait() */ typedef int pthread_mutexattr_t; #define win_pthread_self my_thread_var->pthread_self #ifdef OS2 -#define pthread_handler_t EXTERN_C void * _Optlink +#define pthread_handler_t EXTERNC void * _Optlink typedef void * (_Optlink *pthread_handler)(void *); #else -#define pthread_handler_t EXTERN_C void * __cdecl +#define pthread_handler_t EXTERNC void * __cdecl typedef void * (__cdecl *pthread_handler)(void *); #endif @@ -187,7 +187,7 @@ typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */ #define pthread_key_create(A,B) thr_keycreate((A),(B)) #define pthread_key_delete(A) thr_keydelete(A) -#define pthread_handler_t EXTERN_C void * +#define pthread_handler_t EXTERNC void * #define pthread_key(T,V) pthread_key_t V void * my_pthread_getspecific_imp(pthread_key_t key); @@ -265,7 +265,7 @@ extern int my_pthread_getprio(pthread_t thread_id); #define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) #define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) #define pthread_detach_this_thread() -#define pthread_handler_t EXTERN_C void * +#define pthread_handler_t EXTERNC void * typedef void *(* pthread_handler)(void *); /* Test first for RTS or FSU threads */ From bc2961dc1a37d79f9a042cc2310c7809e2f3a4ad Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Oct 2005 17:45:30 +0400 Subject: [PATCH 5/5] Formatting change for #14137 patch. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a0a5864ebee..94d3c4c332c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7155,7 +7155,7 @@ static void fix_paths(void) CHARSET_DIR, NullS); } (void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff); - convert_dirname(mysql_charsets_dir,mysql_charsets_dir,NullS); + convert_dirname(mysql_charsets_dir, mysql_charsets_dir, NullS); charsets_dir=mysql_charsets_dir; if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir))