diff options
-rw-r--r-- | mysql-test/r/timezone2.result | 8 | ||||
-rw-r--r-- | mysql-test/t/timezone2.test | 17 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 30 | ||||
-rw-r--r-- | sql/item_timefunc.h | 8 | ||||
-rw-r--r-- | sql/set_var.cc | 28 | ||||
-rw-r--r-- | sql/set_var.h | 1 | ||||
-rw-r--r-- | sql/tztime.cc | 7 |
7 files changed, 72 insertions, 27 deletions
diff --git a/mysql-test/r/timezone2.result b/mysql-test/r/timezone2.result index 919f4ee5d3e..5ef06ae363b 100644 --- a/mysql-test/r/timezone2.result +++ b/mysql-test/r/timezone2.result @@ -305,3 +305,11 @@ delete from mysql.db where user like 'mysqltest\_%'; delete from mysql.tables_priv where user like 'mysqltest\_%'; flush privileges; drop table t1, t2; +select convert_tz('2005-01-14 17:00:00', 'UTC', custTimeZone) from (select 'UTC' as custTimeZone) as tmp; +convert_tz('2005-01-14 17:00:00', 'UTC', custTimeZone) +2005-01-14 17:00:00 +create table t1 select convert_tz(NULL, NULL, NULL); +select * from t1; +convert_tz(NULL, NULL, NULL) +NULL +drop table t1; diff --git a/mysql-test/t/timezone2.test b/mysql-test/t/timezone2.test index 5b5d2aa774e..05736b92ad6 100644 --- a/mysql-test/t/timezone2.test +++ b/mysql-test/t/timezone2.test @@ -266,3 +266,20 @@ delete from mysql.db where user like 'mysqltest\_%'; delete from mysql.tables_priv where user like 'mysqltest\_%'; flush privileges; drop table t1, t2; + +# +# Test for bug #7705 "CONVERT_TZ() crashes with subquery/WHERE on index +# column". Queries in which one of time zone arguments of CONVERT_TZ() is +# determined as constant only at val() stage (not at fix_fields() stage), +# should not crash server. +# +select convert_tz('2005-01-14 17:00:00', 'UTC', custTimeZone) from (select 'UTC' as custTimeZone) as tmp; + +# +# Test for bug #7899 "CREATE TABLE .. SELECT .. and CONVERT_TZ() function +# does not work well together". The following statement should return only +# one NULL row and not result of full join. +# +create table t1 select convert_tz(NULL, NULL, NULL); +select * from t1; +drop table t1; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 5a069aee554..3d1feee1f8c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1662,6 +1662,7 @@ void Item_func_convert_tz::fix_length_and_dec() collation.set(&my_charset_bin); decimals= 0; max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; + maybe_null= 1; } @@ -1674,12 +1675,6 @@ Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **re tz_tables= thd_arg->lex->time_zone_tables_used; - if (args[1]->const_item()) - from_tz= my_tz_find(args[1]->val_str(&str), tz_tables); - - if (args[2]->const_item()) - to_tz= my_tz_find(args[2]->val_str(&str), tz_tables); - return FALSE; } @@ -1719,13 +1714,19 @@ bool Item_func_convert_tz::get_date(TIME *ltime, my_time_t my_time_tmp; bool not_used; String str; - - if (!args[1]->const_item()) + + if (!from_tz_cached) + { from_tz= my_tz_find(args[1]->val_str(&str), tz_tables); - - if (!args[2]->const_item()) + from_tz_cached= args[1]->const_item(); + } + + if (!to_tz_cached) + { to_tz= my_tz_find(args[2]->val_str(&str), tz_tables); - + to_tz_cached= args[2]->const_item(); + } + if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, TIME_NO_ZERO_DATE)) { null_value= 1; @@ -1747,6 +1748,13 @@ bool Item_func_convert_tz::get_date(TIME *ltime, } +void Item_func_convert_tz::cleanup() +{ + from_tz_cached= to_tz_cached= 0; + Item_date_func::cleanup(); +} + + void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index dccba7f52b1..917018463e5 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -545,12 +545,15 @@ class Item_func_convert_tz :public Item_date_func TABLE_LIST *tz_tables; /* If time zone parameters are constants we are caching objects that - represent them. + represent them (we use separate from_tz_cached/to_tz_cached members + to indicate this fact, since NULL is legal value for from_tz/to_tz + members. */ + bool from_tz_cached, to_tz_cached; Time_zone *from_tz, *to_tz; public: Item_func_convert_tz(Item *a, Item *b, Item *c): - Item_date_func(a, b, c) {} + Item_date_func(a, b, c), from_tz_cached(0), to_tz_cached(0) {} longlong val_int(); double val_real() { return (double) val_int(); } String *val_str(String *str); @@ -558,6 +561,7 @@ class Item_func_convert_tz :public Item_date_func bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); bool get_date(TIME *res, uint fuzzy_date); + void cleanup(); }; diff --git a/sql/set_var.cc b/sql/set_var.cc index 4d29529b256..7a528467e24 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2505,8 +2505,15 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var) bool sys_var_thd_time_zone::update(THD *thd, set_var *var) { - /* We are using Time_zone object found during check() phase */ - *get_tz_ptr(thd,var->type)= var->save_result.time_zone; + /* We are using Time_zone object found during check() phase. */ + if (var->type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.time_zone= var->save_result.time_zone; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.time_zone= var->save_result.time_zone; return 0; } @@ -2518,27 +2525,25 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type, We can use ptr() instead of c_ptr() here because String contaning time zone name is guaranteed to be zero ended. */ - return (byte *)((*get_tz_ptr(thd,type))->get_name()->ptr()); -} - - -Time_zone** sys_var_thd_time_zone::get_tz_ptr(THD *thd, - enum_var_type type) -{ if (type == OPT_GLOBAL) - return &global_system_variables.time_zone; + return (byte *)(global_system_variables.time_zone->get_name()->ptr()); else - return &thd->variables.time_zone; + return (byte *)(thd->variables.time_zone->get_name()->ptr()); } void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type) { + pthread_mutex_lock(&LOCK_global_system_variables); if (type == OPT_GLOBAL) { if (default_tz_name) { String str(default_tz_name, &my_charset_latin1); + /* + We are guaranteed to find this time zone since its existence + is checked during start-up. + */ global_system_variables.time_zone= my_tz_find(&str, thd->lex->time_zone_tables_used); } @@ -2547,6 +2552,7 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type) } else thd->variables.time_zone= global_system_variables.time_zone; + pthread_mutex_unlock(&LOCK_global_system_variables); } diff --git a/sql/set_var.h b/sql/set_var.h index 0f30f764ed5..8514b518660 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -724,7 +724,6 @@ public: bool update(THD *thd, set_var *var); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); virtual void set_default(THD *thd, enum_var_type type); - Time_zone **get_tz_ptr(THD *thd, enum_var_type type); }; diff --git a/sql/tztime.cc b/sql/tztime.cc index 4b769aed40c..b2b3576e221 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1807,8 +1807,11 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) 0, HA_READ_KEY_EXACT)) { #ifdef EXTRA_DEBUG - sql_print_error("Can't find description of time zone '%.*s'", tz_name->length(), - tz_name->ptr()); + /* + Most probably user has mistyped time zone name, so no need to bark here + unless we need it for debugging. + */ + sql_print_error("Can't find description of time zone '%s'", tz_name_buff); #endif goto end; } |