From: Alexander Barkov Date: November 7 2011 12:04pm Subject: bzr push into mysql-trunk branch (alexander.barkov:3550 to 3552) WL#946 List-Archive: http://lists.mysql.com/commits/141864 Message-Id: <201111071204.pA7C4xXU019165@bar.myoffice.izhnet.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3552 Alexander Barkov 2011-11-07 WL#946: more clean-ups in MYSQL_TIME_cache: now set_XXX() functions automatically reset string representation. This is needed because in case of prepared statements fix_length_and_dec() is called twice: at prepare time and at execute time. We need to clean string representation when set_XXX() is called from the execute time fix_length_and_dec(). modified: sql/item_timefunc.cc sql/item_timefunc.h unittest/gunit/item-t.cc 3551 Alexander Barkov 2011-11-07 WL#946: Bug#13354645 CRASH IN ITEM_TEMPORAL_HYBRID_FUNC modified: mysql-test/r/type_temporal_fractional.result mysql-test/t/type_temporal_fractional.test sql/item_timefunc.cc sql/sql_time.h 3550 Alexander Barkov 2011-11-07 WL#946 Improvements in MYSQL_TIME_cache. modified: sql/item_timefunc.cc sql/item_timefunc.h unittest/gunit/item-t.cc === modified file 'mysql-test/r/type_temporal_fractional.result' --- a/mysql-test/r/type_temporal_fractional.result 2011-11-02 06:13:46 +0000 +++ b/mysql-test/r/type_temporal_fractional.result 2011-11-07 11:50:35 +0000 @@ -15969,3 +15969,54 @@ FROM t1 WHERE col_datetime_3_not_null_key NOT IN (LEAST( DATE('0000-00-00 00:00:00'), CURDATE()), col_time_2_key); DROP TABLE t1; +SET timestamp=UNIX_TIMESTAMP('2001-11-07 15:13:00'); +CREATE TABLE t1 ( +col_time_3_not_null time(3) NOT NULL, +col_datetime_4_not_null_key datetime(4) NOT NULL, +col_datetime_key datetime DEFAULT NULL, +col_time_1_key time(1) DEFAULT NULL, +col_time_5 time(5) DEFAULT NULL, +col_timestamp_6_not_null_key timestamp(6) NULL DEFAULT '0000-00-00 00:00:00.000000', +pk datetime(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000', +PRIMARY KEY (pk), +KEY col_datetime_4_not_null_key (col_datetime_4_not_null_key), +KEY col_datetime_key (col_datetime_key), +KEY col_time_1_key (col_time_1_key), +KEY col_timestamp_6_not_null_key (col_timestamp_6_not_null_key)); +INSERT INTO t1 VALUES ('12:52:24.022','0000-00-00 00:00:00.0000','2003-05-24 00:00:00','00:20:09.0','15:11:20.03463','0000-00-00 00:00:00.000000','2011-11-07 12:01:35.111932'); +INSERT INTO t1 VALUES ('18:52:49.043','2000-10-13 00:00:00.0000','2005-07-22 00:00:00',NULL,'08:19:02.03845','2000-09-20 03:26:09.009008','2011-11-07 12:01:36.111932'); +INSERT INTO t1 VALUES ('23:46:05.010','2005-12-27 04:06:15.0087','0000-00-00 00:00:00','23:40:13.0','08:30:24.03114','0000-00-00 00:00:00.000000','2011-11-07 12:01:37.111932'); +INSERT INTO t1 VALUES ('00:20:05.000','2009-06-01 08:01:58.0532','2007-03-26 12:18:48','00:20:03.0','20:32:22.04519','2000-08-19 21:00:00.000000','2011-11-07 12:01:38.111932'); +INSERT INTO t1 VALUES ('00:20:05.000','2002-05-01 00:00:00.0000','0000-00-00 00:00:00','04:31:10.0','00:20:04.00000','0000-00-00 00:00:00.000000','2011-11-07 12:01:39.111932'); +INSERT INTO t1 VALUES ('00:20:06.000','2007-07-25 22:20:58.0023','0000-00-00 00:00:00','00:23:16.1',NULL,'2008-03-19 16:17:15.042024','2011-11-07 12:01:40.111932'); +INSERT INTO t1 VALUES ('02:55:32.040','0000-00-00 00:00:00.0000',NULL,'00:20:02.0','08:45:57.00998','2009-06-25 10:21:16.011345','2011-11-07 12:01:41.111932'); +INSERT INTO t1 VALUES ('00:20:06.000','2009-01-07 01:12:15.0324','2000-05-26 00:00:00','17:41:45.1','00:20:07.00000','0000-00-00 00:00:00.000000','2011-11-07 12:01:42.111932'); +INSERT INTO t1 VALUES ('12:01:30.061','2009-04-01 00:00:00.0000','2001-05-08 05:31:04','07:43:41.1','11:12:29.03251','2009-12-22 17:45:46.040987','2011-11-07 12:01:43.111932'); +INSERT INTO t1 VALUES ('00:16:22.057','2005-05-10 00:18:58.0345',NULL,'02:24:15.0',NULL,'2008-02-14 20:55:46.023678','2011-11-07 12:01:44.111932'); +INSERT INTO t1 VALUES ('06:54:17.018','2002-12-27 12:28:03.0382','0000-00-00 00:00:00','19:19:54.0','01:42:30.03406','0000-00-00 00:00:00.000000','2011-11-07 12:01:45.111932'); +INSERT INTO t1 VALUES ('00:20:04.000','2007-03-11 00:00:00.0000','0000-00-00 00:00:00',NULL,'13:12:03.05778','2005-02-19 02:31:13.046418','2011-11-07 12:01:46.111932'); +INSERT INTO t1 VALUES ('00:20:01.000','2009-08-13 00:00:00.0000','0000-00-00 00:00:00','00:20:02.0',NULL,'2008-05-21 10:53:59.004633','2011-11-07 12:01:47.111932'); +INSERT INTO t1 VALUES ('02:44:13.025','2001-07-02 14:06:37.0411','2009-04-01 00:43:45','00:20:07.0','16:15:02.01279','2004-07-28 17:34:20.031118','2011-11-07 12:01:48.111932'); +INSERT INTO t1 VALUES ('14:51:02.019','2006-02-24 04:12:05.0014','0000-00-00 00:00:00','00:20:08.0','00:20:09.00000','2001-04-25 21:00:00.000000','2011-11-07 12:01:49.111932'); +SELECT +col_timestamp_6_not_null_key AS c1, +col_datetime_key AS c2, +UTC_DATE() AS c3 +FROM t1 +WHERE col_time_1_key BETWEEN +TIMESTAMPADD(MONTH, 38 ,CONVERT_TZ( DATE(MAKEDATE(207, 38 )), '+00:00','+04:00')) +AND LOCALTIMESTAMP() +ORDER BY col_datetime_4_not_null_key , col_time_5 , col_time_3_not_null; +c1 c2 c3 +2009-06-25 10:21:16.011345 NULL 2001-11-07 +0000-00-00 00:00:00.000000 2003-05-24 00:00:00 2001-11-07 +2004-07-28 17:34:20.031118 2009-04-01 00:43:45 2001-11-07 +0000-00-00 00:00:00.000000 0000-00-00 00:00:00 2001-11-07 +2008-02-14 20:55:46.023678 NULL 2001-11-07 +2001-04-25 21:00:00.000000 0000-00-00 00:00:00 2001-11-07 +2008-03-19 16:17:15.042024 0000-00-00 00:00:00 2001-11-07 +2009-12-22 17:45:46.040987 2001-05-08 05:31:04 2001-11-07 +2000-08-19 21:00:00.000000 2007-03-26 12:18:48 2001-11-07 +2008-05-21 10:53:59.004633 0000-00-00 00:00:00 2001-11-07 +DROP TABLE t1; +SET timestamp=DEFAULT; === modified file 'mysql-test/t/type_temporal_fractional.test' --- a/mysql-test/t/type_temporal_fractional.test 2011-11-02 06:13:46 +0000 +++ b/mysql-test/t/type_temporal_fractional.test 2011-11-07 11:50:35 +0000 @@ -6765,6 +6765,49 @@ WHERE col_datetime_3_not_null_key NOT IN --enable_result_log DROP TABLE t1; +# +# Bug#13354645 CRASH IN ITEM_TEMPORAL_HYBRID_FUNC +# +SET timestamp=UNIX_TIMESTAMP('2001-11-07 15:13:00'); +CREATE TABLE t1 ( + col_time_3_not_null time(3) NOT NULL, + col_datetime_4_not_null_key datetime(4) NOT NULL, + col_datetime_key datetime DEFAULT NULL, + col_time_1_key time(1) DEFAULT NULL, + col_time_5 time(5) DEFAULT NULL, + col_timestamp_6_not_null_key timestamp(6) NULL DEFAULT '0000-00-00 00:00:00.000000', + pk datetime(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000', + PRIMARY KEY (pk), + KEY col_datetime_4_not_null_key (col_datetime_4_not_null_key), + KEY col_datetime_key (col_datetime_key), + KEY col_time_1_key (col_time_1_key), + KEY col_timestamp_6_not_null_key (col_timestamp_6_not_null_key)); +INSERT INTO t1 VALUES ('12:52:24.022','0000-00-00 00:00:00.0000','2003-05-24 00:00:00','00:20:09.0','15:11:20.03463','0000-00-00 00:00:00.000000','2011-11-07 12:01:35.111932'); +INSERT INTO t1 VALUES ('18:52:49.043','2000-10-13 00:00:00.0000','2005-07-22 00:00:00',NULL,'08:19:02.03845','2000-09-20 03:26:09.009008','2011-11-07 12:01:36.111932'); +INSERT INTO t1 VALUES ('23:46:05.010','2005-12-27 04:06:15.0087','0000-00-00 00:00:00','23:40:13.0','08:30:24.03114','0000-00-00 00:00:00.000000','2011-11-07 12:01:37.111932'); +INSERT INTO t1 VALUES ('00:20:05.000','2009-06-01 08:01:58.0532','2007-03-26 12:18:48','00:20:03.0','20:32:22.04519','2000-08-19 21:00:00.000000','2011-11-07 12:01:38.111932'); +INSERT INTO t1 VALUES ('00:20:05.000','2002-05-01 00:00:00.0000','0000-00-00 00:00:00','04:31:10.0','00:20:04.00000','0000-00-00 00:00:00.000000','2011-11-07 12:01:39.111932'); +INSERT INTO t1 VALUES ('00:20:06.000','2007-07-25 22:20:58.0023','0000-00-00 00:00:00','00:23:16.1',NULL,'2008-03-19 16:17:15.042024','2011-11-07 12:01:40.111932'); +INSERT INTO t1 VALUES ('02:55:32.040','0000-00-00 00:00:00.0000',NULL,'00:20:02.0','08:45:57.00998','2009-06-25 10:21:16.011345','2011-11-07 12:01:41.111932'); +INSERT INTO t1 VALUES ('00:20:06.000','2009-01-07 01:12:15.0324','2000-05-26 00:00:00','17:41:45.1','00:20:07.00000','0000-00-00 00:00:00.000000','2011-11-07 12:01:42.111932'); +INSERT INTO t1 VALUES ('12:01:30.061','2009-04-01 00:00:00.0000','2001-05-08 05:31:04','07:43:41.1','11:12:29.03251','2009-12-22 17:45:46.040987','2011-11-07 12:01:43.111932'); +INSERT INTO t1 VALUES ('00:16:22.057','2005-05-10 00:18:58.0345',NULL,'02:24:15.0',NULL,'2008-02-14 20:55:46.023678','2011-11-07 12:01:44.111932'); +INSERT INTO t1 VALUES ('06:54:17.018','2002-12-27 12:28:03.0382','0000-00-00 00:00:00','19:19:54.0','01:42:30.03406','0000-00-00 00:00:00.000000','2011-11-07 12:01:45.111932'); +INSERT INTO t1 VALUES ('00:20:04.000','2007-03-11 00:00:00.0000','0000-00-00 00:00:00',NULL,'13:12:03.05778','2005-02-19 02:31:13.046418','2011-11-07 12:01:46.111932'); +INSERT INTO t1 VALUES ('00:20:01.000','2009-08-13 00:00:00.0000','0000-00-00 00:00:00','00:20:02.0',NULL,'2008-05-21 10:53:59.004633','2011-11-07 12:01:47.111932'); +INSERT INTO t1 VALUES ('02:44:13.025','2001-07-02 14:06:37.0411','2009-04-01 00:43:45','00:20:07.0','16:15:02.01279','2004-07-28 17:34:20.031118','2011-11-07 12:01:48.111932'); +INSERT INTO t1 VALUES ('14:51:02.019','2006-02-24 04:12:05.0014','0000-00-00 00:00:00','00:20:08.0','00:20:09.00000','2001-04-25 21:00:00.000000','2011-11-07 12:01:49.111932'); +SELECT + col_timestamp_6_not_null_key AS c1, + col_datetime_key AS c2, + UTC_DATE() AS c3 +FROM t1 +WHERE col_time_1_key BETWEEN + TIMESTAMPADD(MONTH, 38 ,CONVERT_TZ( DATE(MAKEDATE(207, 38 )), '+00:00','+04:00')) + AND LOCALTIMESTAMP() +ORDER BY col_datetime_4_not_null_key , col_time_5 , col_time_3_not_null; +DROP TABLE t1; +SET timestamp=DEFAULT; ## TS-TODO: SELECT CAST('00:00:00' AS DATETIME) -> should it use curdate? ## TS-TODO: Item::get_date() works via string for DECIMAL_RESULT/FLOAT_RESULT: select cast(20110512154559.616 as date) === modified file 'sql/item_timefunc.cc' --- a/sql/item_timefunc.cc 2011-11-07 07:44:22 +0000 +++ b/sql/item_timefunc.cc 2011-11-07 12:02:15 +0000 @@ -1800,62 +1800,64 @@ bool Item_func_from_days::get_date(MYSQL void MYSQL_TIME_cache::set_time(MYSQL_TIME *ltime, uint8 dec_arg) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME); time= *ltime; time_packed= TIME_to_longlong_time_packed(&time); dec= dec_arg; + reset_string(); } void MYSQL_TIME_cache::set_date(MYSQL_TIME *ltime) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE); time= *ltime; time_packed= TIME_to_longlong_date_packed(&time); + dec= 0; + reset_string(); } void MYSQL_TIME_cache::set_datetime(MYSQL_TIME *ltime, uint8 dec_arg) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATETIME); time= *ltime; time_packed= TIME_to_longlong_datetime_packed(&time); dec= dec_arg; + reset_string(); } void MYSQL_TIME_cache::set_datetime(struct timeval tv, uint8 dec_arg, Time_zone *tz) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); tz->gmt_sec_to_TIME(&time, tv); time_packed= TIME_to_longlong_datetime_packed(&time); dec= dec_arg; + reset_string(); } void MYSQL_TIME_cache::set_date(struct timeval tv, Time_zone *tz) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); tz->gmt_sec_to_TIME(&time, (my_time_t) tv.tv_sec); time.time_type= MYSQL_TIMESTAMP_DATE; /* We don't need to set second_part and neg because they are already 0 */ time.hour= time.minute= time.second= 0; time_packed= TIME_to_longlong_date_packed(&time); + dec= 0; + reset_string(); } void MYSQL_TIME_cache::set_time(struct timeval tv, uint8 dec_arg, Time_zone *tz) { - DBUG_ASSERT(string_buff[0] == '\0' && string_length == 0); tz->gmt_sec_to_TIME(&time, tv); datetime_to_time(&time); time_packed= TIME_to_longlong_time_packed(&time); dec= dec_arg; + reset_string(); } @@ -2373,6 +2375,17 @@ bool Item_date_add_interval::get_date_in if (date_sub_interval) interval.neg = !interval.neg; + /* + Make sure we return proper time_type. + It's important for val_str(). + */ + if (cached_field_type == MYSQL_TYPE_DATE && + ltime->time_type == MYSQL_TIMESTAMP_DATETIME) + datetime_to_date(ltime); + else if (cached_field_type == MYSQL_TYPE_DATETIME && + ltime->time_type == MYSQL_TIMESTAMP_DATE) + date_to_datetime(ltime); + if ((null_value= date_add_interval(ltime, int_type, interval))) return true; return false; === modified file 'sql/item_timefunc.h' --- a/sql/item_timefunc.h 2011-11-07 07:44:22 +0000 +++ b/sql/item_timefunc.h 2011-11-07 12:02:15 +0000 @@ -677,11 +677,13 @@ class MYSQL_TIME_cache If string representation has already been cached, then nothing happens. */ void cache_string(); -public: - - MYSQL_TIME_cache() + /** + Reset string representation. + */ + void reset_string() { - reset(); + string_length= 0; + string_buff[0]= '\0'; } /** Reset all members. @@ -690,10 +692,15 @@ public: { time.time_type= MYSQL_TIMESTAMP_NONE; time_packed= 0; - string_length= 0; - string_buff[0]= '\0'; + reset_string(); dec= 0; } +public: + + MYSQL_TIME_cache() + { + reset(); + } /** Set time and time_packed from a DATE value. */ === modified file 'sql/sql_time.h' --- a/sql/sql_time.h 2011-11-02 11:21:10 +0000 +++ b/sql/sql_time.h 2011-11-07 11:50:35 +0000 @@ -53,6 +53,15 @@ inline void datetime_to_time(MYSQL_TIME ltime->year= ltime->month= ltime->day= 0; ltime->time_type= MYSQL_TIMESTAMP_TIME; } +inline void datetime_to_date(MYSQL_TIME *ltime) +{ + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + ltime->time_type= MYSQL_TIMESTAMP_DATE; +} +inline void date_to_datetime(MYSQL_TIME *ltime) +{ + ltime->time_type= MYSQL_TIMESTAMP_DATETIME; +} void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, ErrConvString val, === modified file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 2011-11-07 07:44:22 +0000 +++ b/unittest/gunit/item-t.cc 2011-11-07 12:02:15 +0000 @@ -414,7 +414,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07 10:20:30.123456", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07 10:20:30.123456", cache.cptr()); - cache.reset(); cache.set_datetime(&datetime6, 6); // Now call the other way around: cptr() then val_str() EXPECT_STREQ("2011-11-07 10:20:30.123456", cache.cptr()); @@ -446,7 +445,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) Testing DATETIME(6). Initializing from "struct timeval". */ - cache.reset(); cache.set_datetime(tv6, 6, my_tz_UTC); EXPECT_EQ(1840440237558456896LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); @@ -458,7 +456,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) Testing TIME(6). Initializing from MYSQL_TIME. */ - cache.reset(); cache.set_time(&time6, 6); EXPECT_EQ(709173043776LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); @@ -471,7 +468,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) Testing TIME(6). Initializing from "struct timeval". */ - cache.reset(); cache.set_time(tv6, 6, my_tz_UTC); EXPECT_EQ(709173043776LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); @@ -482,7 +478,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) /* Testing DATETIME(5) */ - cache.reset(); MYSQL_TIME datetime5= { 2011, 11, 7, 10, 20, 30, 123450, 0, MYSQL_TIMESTAMP_DATETIME }; cache.set_datetime(&datetime5, 5); @@ -492,7 +487,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07 10:20:30.12345", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07 10:20:30.12345", cache.cptr()); - cache.reset(); cache.set_datetime(&datetime5, 5); /* Now call the other way around: cptr() then val_str() */ EXPECT_STREQ("2011-11-07 10:20:30.12345", cache.cptr()); @@ -502,7 +496,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) Testing DATE. Initializing from MYSQL_TIME. */ - cache.reset(); MYSQL_TIME date= { 2011, 11, 7, 0, 0, 0, 0, 0, MYSQL_TIMESTAMP_DATE }; cache.set_date(&date); @@ -516,7 +509,6 @@ TEST_F(ItemTest, MYSQL_TIME_cache) Testing DATE. Initializing from "struct tm". */ - cache.reset(); cache.set_date(tv6, my_tz_UTC); EXPECT_EQ(1840439528385413120LL, cache.val_packed()); EXPECT_EQ(0, cache.decimals()); No bundle (reason: useless for push emails).