summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/timezone2.result7
-rw-r--r--mysql-test/t/timezone2.test12
-rw-r--r--scripts/mysql_create_system_tables.sh11
-rw-r--r--sql/item_create.cc5
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_timefunc.cc28
-rw-r--r--sql/item_timefunc.h16
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/set_var.cc8
-rw-r--r--sql/set_var.h1
-rw-r--r--sql/sql_base.cc17
-rw-r--r--sql/sql_lex.cc37
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_select.cc33
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/tztime.cc306
-rw-r--r--sql/tztime.h3
20 files changed, 315 insertions, 199 deletions
diff --git a/mysql-test/r/timezone2.result b/mysql-test/r/timezone2.result
index 5361ff4ffe6..02406b77a65 100644
--- a/mysql-test/r/timezone2.result
+++ b/mysql-test/r/timezone2.result
@@ -244,3 +244,10 @@ NULL
select convert_tz( NULL, 'MET', 'UTC');
convert_tz( NULL, 'MET', 'UTC')
NULL
+create table t1 (ts timestamp);
+set timestamp=1000000000;
+insert into t1 (ts) values (now());
+select convert_tz(ts, @@time_zone, 'Japan') from t1;
+convert_tz(ts, @@time_zone, 'Japan')
+2001-09-09 10:46:40
+drop table t1;
diff --git a/mysql-test/t/timezone2.test b/mysql-test/t/timezone2.test
index 49579421570..15ac3416b29 100644
--- a/mysql-test/t/timezone2.test
+++ b/mysql-test/t/timezone2.test
@@ -187,3 +187,15 @@ select convert_tz('2003-12-31 04:00:00', 'SomeNotExistingTimeZone', 'UTC');
select convert_tz('2003-12-31 04:00:00', 'MET', 'SomeNotExistingTimeZone');
select convert_tz('2003-12-31 04:00:00', 'MET', NULL);
select convert_tz( NULL, 'MET', 'UTC');
+
+#
+# Test for bug #4508 "CONVERT_TZ() function with new time zone as param
+# crashes server." (Was caused by improperly worked mechanism of time zone
+# dynamical loading).
+#
+create table t1 (ts timestamp);
+set timestamp=1000000000;
+insert into t1 (ts) values (now());
+select convert_tz(ts, @@time_zone, 'Japan') from t1;
+drop table t1;
+
diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh
index e45c0ec5571..7a30bcdbeca 100644
--- a/scripts/mysql_create_system_tables.sh
+++ b/scripts/mysql_create_system_tables.sh
@@ -307,7 +307,8 @@ then
then
i_tzn="$i_tzn INSERT INTO time_zone_name (Name, Time_Zone_id) VALUES"
i_tzn="$i_tzn ('MET', 1), ('UTC', 2), ('Universal', 2), "
- i_tzn="$i_tzn ('Europe/Moscow',3), ('leap/Europe/Moscow',4);"
+ i_tzn="$i_tzn ('Europe/Moscow',3), ('leap/Europe/Moscow',4), "
+ i_tzn="$i_tzn ('Japan', 5);"
fi
fi
@@ -327,7 +328,7 @@ then
if test "$1" = "test"
then
i_tz="$i_tz INSERT INTO time_zone (Time_zone_id, Use_leap_seconds)"
- i_tz="$i_tz VALUES (1,'N'), (2,'N'), (3,'N'), (4,'Y');"
+ i_tz="$i_tz VALUES (1,'N'), (2,'N'), (3,'N'), (4,'Y'), (5,'N');"
fi
fi
@@ -546,7 +547,8 @@ then
i_tzt="$i_tzt ,(4, 2045689222, 8) ,(4, 2058390022, 9)"
i_tzt="$i_tzt ,(4, 2077138822, 8) ,(4, 2090444422, 9)"
i_tzt="$i_tzt ,(4, 2108588422, 8) ,(4, 2121894022, 9)"
- i_tzt="$i_tzt ,(4, 2140038022, 8);"
+ i_tzt="$i_tzt ,(4, 2140038022, 8)"
+ i_tzt="$i_tzt ,(5, -1009875600, 1);"
fi
fi
@@ -584,7 +586,8 @@ then
i_tztt="$i_tztt ,(4, 4, 10800, 0, 'MSK') ,(4, 5, 14400, 1, 'MSD')"
i_tztt="$i_tztt ,(4, 6, 18000, 1, 'MSD') ,(4, 7, 7200, 0, 'EET')"
i_tztt="$i_tztt ,(4, 8, 10800, 0, 'MSK') ,(4, 9, 14400, 1, 'MSD')"
- i_tztt="$i_tztt ,(4, 10, 10800, 1, 'EEST') ,(4, 11, 7200, 0, 'EET');"
+ i_tztt="$i_tztt ,(4, 10, 10800, 1, 'EEST') ,(4, 11, 7200, 0, 'EET')"
+ i_tztt="$i_tztt ,(5, 0, 32400, 0, 'CJT') ,(5, 1, 32400, 0, 'JST');"
fi
fi
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 4290a25e348..c98c7892c26 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -89,11 +89,6 @@ Item *create_func_conv(Item* a, Item *b, Item *c)
return new Item_func_conv(a,b,c);
}
-Item *create_func_convert_tz(Item* a, Item *b, Item *c)
-{
- return new Item_func_convert_tz(a,b,c);
-}
-
Item *create_func_cos(Item* a)
{
return new Item_func_cos(a);
diff --git a/sql/item_create.h b/sql/item_create.h
index 19f0c9133f2..7577627ef04 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -31,7 +31,6 @@ Item *create_func_char_length(Item* a);
Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
-Item *create_func_convert_tz(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
Item *create_func_cot(Item* a);
Item *create_func_crc32(Item* a);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index cc320addd47..73aec7e8bdd 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1648,19 +1648,29 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
-{
- String str;
-
- thd= current_thd;
+{
collation.set(&my_charset_bin);
decimals= 0;
max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+}
+
+
+bool
+Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref)
+{
+ String str;
+ if (Item_date_func::fix_fields(thd_arg, tables_arg, ref))
+ return 1;
+
+ tz_tables= thd_arg->lex->time_zone_tables_used;
if (args[1]->const_item())
- from_tz= my_tz_find(thd, args[1]->val_str(&str));
-
+ from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
+
if (args[2]->const_item())
- to_tz= my_tz_find(thd, args[2]->val_str(&str));
+ to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
+
+ return 0;
}
@@ -1701,10 +1711,10 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
String str;
if (!args[1]->const_item())
- from_tz= my_tz_find(thd, args[1]->val_str(&str));
+ from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
if (!args[2]->const_item())
- to_tz= my_tz_find(thd, args[2]->val_str(&str));
+ to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, 0))
{
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index a7ff2924786..2254fc830c9 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -531,9 +531,22 @@ class Item_func_from_unixtime :public Item_date_func
*/
class Time_zone;
+/*
+ This class represents CONVERT_TZ() function.
+ The important fact about this function that it is handled in special way.
+ When such function is met in expression time_zone system tables are added
+ to global list of tables to open, so later those already opened and locked
+ tables can be used during this function calculation for loading time zone
+ descriptions.
+*/
class Item_func_convert_tz :public Item_date_func
{
- THD *thd;
+ /* Cached pointer to list of pre-opened time zone tables. */
+ TABLE_LIST *tz_tables;
+ /*
+ If time zone parameters are constants we are caching objects that
+ represent them.
+ */
Time_zone *from_tz, *to_tz;
public:
Item_func_convert_tz(Item *a, Item *b, Item *c):
@@ -542,6 +555,7 @@ class Item_func_convert_tz :public Item_date_func
double val() { return (double) val_int(); }
String *val_str(String *str);
const char *func_name() const { return "convert_tz"; }
+ bool fix_fields(THD *, struct st_table_list *, Item **);
void fix_length_and_dec();
bool get_date(TIME *res, uint fuzzy_date);
};
diff --git a/sql/lex.h b/sql/lex.h
index 218a1762a5c..c64a7069c32 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -499,7 +499,7 @@ static SYMBOL sql_functions[] = {
{ "CONNECTION_ID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
{ "CONTAINS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_contains)},
{ "CONV", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
- { "CONVERT_TZ", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_convert_tz)},
+ { "CONVERT_TZ", SYM(CONVERT_TZ_SYM)},
{ "COUNT", SYM(COUNT_SYM)},
{ "COS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2f0e2085430..b3b79c16787 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -500,7 +500,6 @@ int mysql_select(THD *thd, Item ***rref_pointer_array,
select_result *result, SELECT_LEX_UNIT *unit,
SELECT_LEX *select_lex);
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
-void fix_tables_pointers(SELECT_LEX *select_lex);
int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index bcebb62ae4d..fc1332695d6 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2372,8 +2372,9 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
return 1;
}
#endif
-
- if (!(var->save_result.time_zone= my_tz_find(thd, res)))
+
+ if (!(var->save_result.time_zone=
+ my_tz_find(res, thd->lex->time_zone_tables_used)))
{
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
return 1;
@@ -2418,7 +2419,8 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
if (default_tz_name)
{
String str(default_tz_name, &my_charset_latin1);
- global_system_variables.time_zone= my_tz_find(thd, &str);
+ global_system_variables.time_zone=
+ my_tz_find(&str, thd->lex->time_zone_tables_used);
}
else
global_system_variables.time_zone= my_tz_SYSTEM;
diff --git a/sql/set_var.h b/sql/set_var.h
index a51e44285d6..4a4e631d88c 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -908,6 +908,7 @@ ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
extern sys_var_str sys_init_connect;
extern sys_var_str sys_init_slave;
+extern sys_var_thd_time_zone sys_time_zone;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
NAMED_LIST **found);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index dd8283e057a..4efdd3edbcd 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1670,7 +1670,22 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
uint counter;
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(-1); /* purecov: inspected */
- fix_tables_pointers(thd->lex->all_selects_list);
+ /*
+ Let us propagate pointers to open tables from global table list
+ to table lists in particular selects if needed.
+ */
+ if (thd->lex->all_selects_list->next_select_in_list() ||
+ thd->lex->time_zone_tables_used)
+ {
+ for (SELECT_LEX *sl= thd->lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ if (cursor->table_list)
+ cursor->table= cursor->table_list->table;
+ }
DBUG_RETURN(mysql_handle_derived(thd->lex));
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 949eaba7311..2b6a307092c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -22,6 +22,16 @@
#include <m_ctype.h>
#include <hash.h>
+
+/*
+ Fake table list object, pointer to which is used as special value for
+ st_lex::time_zone_tables_used indicating that we implicitly use time
+ zone tables in this statement but real table list was not yet created.
+ Pointer to it is also returned by my_tz_get_tables_list() as indication
+ of transient error;
+*/
+TABLE_LIST fake_time_zone_tables_list;
+
/* Macros to look like lex */
#define yyGet() *(lex->ptr++)
@@ -1292,7 +1302,32 @@ bool st_select_lex_unit::create_total_list(THD *thd_arg, st_lex *lex,
TABLE_LIST **result_arg)
{
*result_arg= 0;
- res= create_total_list_n_last_return(thd_arg, lex, &result_arg);
+ if (!(res= create_total_list_n_last_return(thd_arg, lex, &result_arg)))
+ {
+ /*
+ If time zone tables were used implicitly in statement we should add
+ them to global table list.
+ */
+ if (lex->time_zone_tables_used)
+ {
+ /*
+ Altough we are modifying lex data, it won't raise any problem in
+ case when this lex belongs to some prepared statement or stored
+ procedure: such modification does not change any invariants imposed
+ by requirement to reuse the same lex for multiple executions.
+ */
+ if ((lex->time_zone_tables_used= my_tz_get_table_list(thd)) !=
+ &fake_time_zone_tables_list)
+ {
+ *result_arg= lex->time_zone_tables_used;
+ }
+ else
+ {
+ send_error(thd, 0);
+ res= 1;
+ }
+ }
+ }
return res;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 5348d5e5646..053c85166f6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -633,6 +633,12 @@ typedef struct st_lex
bool prepared_stmt_code_is_varref;
/* Names of user variables holding parameters (in EXECUTE) */
List<LEX_STRING> prepared_stmt_params;
+ /*
+ If points to fake_time_zone_tables_list indicates that time zone
+ tables are implicitly used by statement, also is used for holding
+ list of those tables after they are opened.
+ */
+ TABLE_LIST *time_zone_tables_used;
st_lex() {}
inline void uncacheable(uint8 cause)
{
@@ -661,6 +667,7 @@ typedef struct st_lex
TABLE_LIST *local_first);
} LEX;
+extern TABLE_LIST fake_time_zone_tables_list;
void lex_init(void);
void lex_free(void);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b69d582f30b..1182f018ea4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1897,7 +1897,8 @@ mysql_execute_command(THD *thd)
#endif
}
#endif /* !HAVE_REPLICATION */
- if (&lex->select_lex != lex->all_selects_list &&
+ if ((&lex->select_lex != lex->all_selects_list ||
+ lex->time_zone_tables_used) &&
lex->unit.create_total_list(thd, lex, &tables))
DBUG_VOID_RETURN;
@@ -3875,6 +3876,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length)
lex->lock_option= TL_READ;
lex->found_colon= 0;
lex->safe_to_cache_query= 1;
+ lex->time_zone_tables_used= 0;
lex_start(thd, buf, length);
thd->select_number= lex->select_lex.select_number= 1;
thd->free_list= 0;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index d8deba2c939..db904d24bf7 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1407,7 +1407,8 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
DBUG_PRINT("enter",("command: %d, param_count: %ld",
sql_command, stmt->param_count));
- if (select_lex != lex->all_selects_list &&
+ if ((&lex->select_lex != lex->all_selects_list ||
+ lex->time_zone_tables_used) &&
lex->unit.create_total_list(thd, lex, &tables))
DBUG_RETURN(1);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3b3d8303210..f8bc6210a2f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -213,39 +213,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
}
-void relink_tables(SELECT_LEX *select_lex)
-{
- for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first;
- cursor;
- cursor=cursor->next)
- if (cursor->table_list)
- cursor->table= cursor->table_list->table;
-}
-
-
-void fix_tables_pointers(SELECT_LEX *select_lex)
-{
- if (select_lex->next_select_in_list())
- {
- /* Fix tables 'to-be-unioned-from' list to point at opened tables */
- for (SELECT_LEX *sl= select_lex;
- sl;
- sl= sl->next_select_in_list())
- relink_tables(sl);
- }
-}
-
-void fix_tables_pointers(SELECT_LEX_UNIT *unit)
-{
- for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
- {
- relink_tables(sl);
- for (SELECT_LEX_UNIT *un= sl->first_inner_unit(); un; un= un->next_unit())
- fix_tables_pointers(un);
- }
-}
-
-
/*
Function to setup clauses without sum functions
*/
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index ccbaf7c0112..5d6ca5d5de5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -463,6 +463,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CASE_SYM
%token CONCAT
%token CONCAT_WS
+%token CONVERT_TZ_SYM
%token CURDATE
%token CURTIME
%token DATABASE
@@ -2825,6 +2826,11 @@ simple_expr:
{ $$= new Item_func_concat(* $3); }
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
+ | CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')'
+ {
+ Lex->time_zone_tables_used= &fake_time_zone_tables_list;
+ $$= new Item_func_convert_tz($3, $5, $7);
+ }
| CURDATE optional_braces
{ $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; }
| CURTIME optional_braces
@@ -5308,6 +5314,12 @@ internal_variable_name:
$$.var= tmp;
$$.base_name.str=0;
$$.base_name.length=0;
+ /*
+ If this is time_zone variable we should open time zone
+ describing tables
+ */
+ if (tmp == &sys_time_zone)
+ Lex->time_zone_tables_used= &fake_time_zone_tables_list;
}
| ident '.' ident
{
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 2ed55f2fa4e..757272d332f 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1359,6 +1359,13 @@ static bool tz_inited= 0;
static uint tz_leapcnt= 0;
static LS_INFO *tz_lsis= 0;
+/*
+ Shows whenever we have found time zone tables during start-up.
+ Used for avoiding of putting those tables to global table list
+ for queries that use time zone info.
+*/
+static bool time_zone_tables_exist= 1;
+
typedef struct st_tz_names_entry: public Sql_alloc
{
@@ -1388,6 +1395,68 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
/*
+ Prepare table list with time zone related tables from preallocated array.
+
+ SYNOPSIS
+ tz_init_table_list()
+ tz_tabs - pointer to preallocated array of 4 TABLE_LIST objects.
+
+ DESCRIPTION
+ This function prepares list of TABLE_LIST objects which can be used
+ for opening of time zone tables from preallocated array.
+*/
+
+void
+tz_init_table_list(TABLE_LIST *tz_tabs)
+{
+ bzero(tz_tabs, sizeof(TABLE_LIST) * 4);
+ tz_tabs[0].alias= tz_tabs[0].real_name= (char*)"time_zone_name";
+ tz_tabs[1].alias= tz_tabs[1].real_name= (char*)"time_zone";
+ tz_tabs[2].alias= tz_tabs[2].real_name= (char*)"time_zone_transition_type";
+ tz_tabs[3].alias= tz_tabs[3].real_name= (char*)"time_zone_transition";
+ tz_tabs[0].next= tz_tabs+1;
+ tz_tabs[1].next= tz_tabs+2;
+ tz_tabs[2].next= tz_tabs+3;
+ tz_tabs[0].lock_type= tz_tabs[1].lock_type= tz_tabs[2].lock_type=
+ tz_tabs[3].lock_type= TL_READ;
+ tz_tabs[0].db= tz_tabs[1].db= tz_tabs[2].db= tz_tabs[3].db= (char *)"mysql";
+}
+
+
+/*
+ Create table list with time zone related tables.
+
+ SYNOPSIS
+ my_tz_get_table_list()
+ thd - current thread object
+
+ DESCRIPTION
+ This function creates list of TABLE_LIST objects allocated in thd's
+ memroot, which can be used for opening of time zone tables.
+
+ RETURN VALUES
+ Returns pointer to first TABLE_LIST object, (could be 0 if time zone
+ tables don't exist) and &fake_time_zone_tables_list in case of error.
+*/
+
+TABLE_LIST *
+my_tz_get_table_list(THD *thd)
+{
+ TABLE_LIST *tz_tabs;
+
+ if (!time_zone_tables_exist)
+ return 0;
+
+ if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) * 4)))
+ return &fake_time_zone_tables_list;
+
+ tz_init_table_list(tz_tabs);
+
+ return tz_tabs;
+}
+
+
+/*
Initialize time zone support infrastructure.
SYNOPSIS
@@ -1399,13 +1468,13 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
DESCRIPTION
This function will init memory structures needed for time zone support,
it will register mandatory SYSTEM time zone in them. It will try to open
- mysql.time_zone_leap_seconds table and and load information which further
- will be shared among all time zones loaded. It will also try to load
- information about default time zone. If system tables with time zone
- descriptions don't exist it won't fail (unless default_tzname is time zone
- from tables). If bootstrap parameter is true then this routine assumes that
- we are in bootstrap mode and won't load time zone descriptions unless someone
- specifies default time zone which is supposedly stored in those tables.
+ mysql.time_zone* tables and load information about default time zone and
+ information which further will be shared among all time zones loaded.
+ If system tables with time zone descriptions don't exist it won't fail
+ (unless default_tzname is time zone from tables). If bootstrap parameter
+ is true then this routine assumes that we are in bootstrap mode and won't
+ load time zone descriptions unless someone specifies default time zone
+ which is supposedly stored in those tables.
It'll also set default time zone if it is specified.
RETURN VALUES
@@ -1416,14 +1485,13 @@ my_bool
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
- TABLE_LIST tables;
+ TABLE_LIST *tables= 0;
+ TABLE_LIST tables_buff[5];
TABLE *table;
- TABLE *lock_ptr;
- MYSQL_LOCK *lock;
TZ_NAMES_ENTRY *tmp_tzname;
my_bool return_val= 1;
int res;
- uint not_used;
+ uint counter;
DBUG_ENTER("my_tz_init");
/*
@@ -1468,7 +1536,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
if (bootstrap)
{
/* If we are in bootstrap mode we should not load time zone tables */
- return_val= 0;
+ return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
@@ -1480,28 +1548,25 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
thd->db= my_strdup("mysql",MYF(0));
thd->db_length= 5; // Safety
- bzero((char*) &tables,sizeof(tables));
- tables.alias= tables.real_name= (char*)"time_zone_leap_second";
- tables.lock_type= TL_READ;
- tables.db= thd->db;
-
- if (open_tables(thd, &tables, &not_used))
+ bzero((char*) &tables_buff, sizeof(TABLE_LIST));
+ tables_buff[0].alias= tables_buff[0].real_name=
+ (char*)"time_zone_leap_second";
+ tables_buff[0].lock_type= TL_READ;
+ tables_buff[0].db= thd->db;
+ tables_buff[0].next= tables_buff + 1;
+ /* Fill TABLE_LIST for rest of the time zone describing tables */
+ tz_init_table_list(tables_buff + 1);
+
+ if (open_tables(thd, tables_buff, &counter) ||
+ lock_tables(thd, tables_buff, counter))
{
- sql_print_error("Warning: Can't open time zone table: %s "
+ sql_print_error("Warning: Can't open and lock time zone table: %s "
"trying to live without them", thd->net.last_error);
/* We will try emulate that everything is ok */
- return_val= 0;
+ return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
-
- lock_ptr= tables.table;
- if (!(lock= mysql_lock_tables(thd, &lock_ptr, 1)))
- {
- sql_print_error("Fatal error: Can't lock time zone table: %s",
- thd->net.last_error);
- goto end_with_close;
- }
-
+ tables= tables_buff + 1;
/*
Now we are going to load leap seconds descriptions that are shared
@@ -1514,11 +1579,16 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
sql_print_error("Fatal error: Out of memory while loading "
"mysql.time_zone_leap_second table");
- goto end_with_unlock;
+ goto end_with_close;
}
- table= tables.table;
- table->file->ha_index_init(0);
+ table= tables_buff[0].table;
+ /*
+ It is OK to ignore ha_index_init()/ha_index_end() return values since
+ mysql.time_zone* tables are MyISAM and these operations always succeed
+ for MyISAM.
+ */
+ (void)table->file->ha_index_init(0);
tz_leapcnt= 0;
res= table->file->index_first(table->record[0]);
@@ -1530,7 +1600,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
sql_print_error("Fatal error: While loading mysql.time_zone_leap_second"
" table: too much leaps");
table->file->ha_index_end();
- goto end_with_unlock;
+ goto end_with_close;
}
tz_lsis[tz_leapcnt].ls_trans= (my_time_t)table->field[0]->val_int();
@@ -1546,13 +1616,13 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
res= table->file->index_next(table->record[0]);
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
if (res != HA_ERR_END_OF_FILE)
{
sql_print_error("Fatal error: Error while loading "
"mysql.time_zone_leap_second table");
- goto end_with_unlock;
+ goto end_with_close;
}
/*
@@ -1562,19 +1632,12 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
return_val= 0;
-end_with_unlock:
- mysql_unlock_tables(thd, lock);
-
-end_with_close:
- close_thread_tables(thd);
- thd->version--; /* Force close to free memory */
-
end_with_setting_default_tz:
- /* If not an error and have default time zone try to load it */
- if (!return_val && default_tzname)
+ /* If we have default time zone try to load it */
+ if (default_tzname)
{
String tzname(default_tzname, &my_charset_latin1);
- if (!(global_system_variables.time_zone= my_tz_find(thd, &tzname)))
+ if (!(global_system_variables.time_zone= my_tz_find(&tzname, tables)))
{
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
default_tzname);
@@ -1582,6 +1645,10 @@ end_with_setting_default_tz:
}
}
+end_with_close:
+ thd->version--; /* Force close to free memory */
+ close_thread_tables(thd);
+
end_with_cleanup:
/* if there were error free time zone describing structs */
@@ -1625,29 +1692,27 @@ void my_tz_free()
Load time zone description from system tables.
SYNOPSIS
- tz_load_from_db()
- thd - current thread object
- tz_name - name of time zone that should be loaded.
+ tz_load_from_open_tables()
+ tz_name - name of time zone that should be loaded.
+ tz_tables - list of tables from which time zone description
+ should be loaded
DESCRIPTION
- This function will try to open system tables describing time zones
- and to load information about time zone specified. It will also update
- information in hash used for time zones lookup.
+ This function will try to load information about time zone specified
+ from the list of the already opened and locked tables (first table in
+ tz_tables should be time_zone_name, next time_zone, then
+ time_zone_transition_type and time_zone_transition should be last).
+ It will also update information in hash used for time zones lookup.
RETURN VALUES
Returns pointer to newly created Time_zone object or 0 in case of error.
*/
+
static Time_zone*
-tz_load_from_db(THD *thd, const String *tz_name)
+tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
{
- TABLE_LIST tables[4];
TABLE *table= 0;
- TABLE *lock_ptr[4];
- MYSQL_LOCK *lock;
- char system_db_name[]= "mysql";
- char *db_save;
- uint db_length_save;
TIME_ZONE_INFO *tz_info;
TZ_NAMES_ENTRY *tmp_tzname;
Time_zone *return_val= 0;
@@ -1667,9 +1732,8 @@ tz_load_from_db(THD *thd, const String *tz_name)
#ifdef ABBR_ARE_USED
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
#endif
- uint not_used;
- DBUG_ENTER("tz_load_from_db");
+ DBUG_ENTER("tz_load_from_open_tables");
/* Prepare tz_info for loading also let us make copy of time zone name */
@@ -1690,76 +1754,45 @@ tz_load_from_db(THD *thd, const String *tz_name)
strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
/*
- Open and lock time zone description tables
- */
- db_save= thd->db;
- db_length_save= thd->db_length;
- thd->db= system_db_name;
- thd->db_length= 5;
-
- bzero((char*) &tables,sizeof(tables));
- tables[0].alias= tables[0].real_name= (char*)"time_zone_name";
- tables[1].alias= tables[1].real_name= (char*)"time_zone";
- tables[2].alias= tables[2].real_name= (char*)"time_zone_transition";
- tables[3].alias= tables[3].real_name= (char*)"time_zone_transition_type";
- tables[0].next= tables+1;
- tables[1].next= tables+2;
- tables[2].next= tables+3;
- tables[0].lock_type= tables[1].lock_type= tables[2].lock_type=
- tables[3].lock_type= TL_READ;
- tables[0].db= tables[1].db= tables[2].db= tables[3].db= thd->db;
- if (open_tables(thd, tables, &not_used))
- {
- sql_print_error("Error: Can't open time zone tables: %s",
- thd->net.last_error);
- goto end;
- }
-
- lock_ptr[0]= tables[0].table;
- lock_ptr[1]= tables[1].table;
- lock_ptr[2]= tables[2].table;
- lock_ptr[3]= tables[3].table;
- if (!(lock= mysql_lock_tables(thd, lock_ptr, 4)))
- {
- sql_print_error("Error: Can't lock time zone tables: %s",
- thd->net.last_error);
- goto end_with_close;
- }
-
- /*
Let us find out time zone id by its name (there is only one index
and it is specifically for this purpose).
*/
- table= tables[0].table;
-
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store(tz_name->ptr(), tz_name->length(), &my_charset_latin1);
- table->file->ha_index_init(0);
+ /*
+ It is OK to ignore ha_index_init()/ha_index_end() return values since
+ mysql.time_zone* tables are MyISAM and these operations always succeed
+ for MyISAM.
+ */
+ (void)table->file->ha_index_init(0);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
{
sql_print_error("Error: Can't find description of time zone.");
- goto end_with_unlock;
+ goto end;
}
tzid= (uint)table->field[1]->val_int();
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
Now we need to lookup record in mysql.time_zone table in order to
understand whenever this timezone uses leap seconds (again we are
using the only index in this table).
*/
- table= tables[1].table;
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
{
sql_print_error("Error: Can't find description of time zone.");
- goto end_with_unlock;
+ goto end;
}
/* If Uses_leap_seconds == 'Y' */
@@ -1769,7 +1802,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
tz_info->lsis= tz_lsis;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
Now we will iterate through records for out time zone in
@@ -1777,9 +1810,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
only for our time zone guess what are we doing?
Right - using special index.
*/
- table= tables[3].table;
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
@@ -1793,7 +1827,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table: too big "
"transition type id");
- goto end_with_unlock;
+ goto end;
}
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
@@ -1807,7 +1841,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table: not enough "
"room for abbreviations");
- goto end_with_unlock;
+ goto end;
}
ttis[ttid].tt_abbrind= tz_info->charcnt;
memcpy(chars + tz_info->charcnt, abbr.ptr(), abbr.length());
@@ -1838,10 +1872,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table");
- goto end_with_unlock;
+ goto end;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
@@ -1849,9 +1883,9 @@ tz_load_from_db(THD *thd, const String *tz_name)
mysql.time_zone_transition table. Here we additionaly need records
in ascending order by index scan also satisfies us.
*/
- table= tables[2].table;
+ table= tz_tables->table;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
@@ -1866,14 +1900,14 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table: "
"too much transitions");
- goto end_with_unlock;
+ goto end;
}
if (ttid + 1 > tz_info->typecnt)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table: "
"bad transition type id");
- goto end_with_unlock;
+ goto end;
}
ats[tz_info->timecnt]= ttime;
@@ -1896,10 +1930,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table");
- goto end_with_unlock;
+ goto end;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
table= 0;
/*
@@ -1916,7 +1950,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
{
sql_print_error("Error: Out of memory while loading time zone "
"description");
- goto end_with_unlock;
+ goto end;
}
@@ -1941,12 +1975,12 @@ tz_load_from_db(THD *thd, const String *tz_name)
if (tz_info->typecnt < 1)
{
sql_print_error("Error: loading time zone without transition types");
- goto end_with_unlock;
+ goto end;
}
if (prepare_tz_info(tz_info, &tz_storage))
{
sql_print_error("Error: Unable to build mktime map for time zone");
- goto end_with_unlock;
+ goto end;
}
@@ -1958,7 +1992,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
my_hash_insert(&tz_names, (const byte *)tmp_tzname)))
{
sql_print_error("Error: Out of memory while loading time zone");
- goto end_with_unlock;
+ goto end;
}
/*
@@ -1966,19 +2000,11 @@ tz_load_from_db(THD *thd, const String *tz_name)
*/
return_val= tmp_tzname->tz;
-end_with_unlock:
+end:
if (table)
- table->file->ha_index_end();
-
- mysql_unlock_tables(thd, lock);
+ (void)table->file->ha_index_end();
-end_with_close:
- close_thread_tables(thd);
-
-end:
- thd->db= db_save;
- thd->db_length= db_length_save;
DBUG_RETURN(return_val);
}
@@ -2068,8 +2094,8 @@ str_to_offset(const char *str, uint length, long *offset)
SYNOPSIS
my_tz_find()
- thd - current thread
name - time zone specification
+ tz_tables - list of opened'n'locked time zone describing tables
DESCRIPTION
This function checks if name is one of time zones described in db,
@@ -2091,7 +2117,11 @@ str_to_offset(const char *str, uint length, long *offset)
values as parameter without additional external check and this property
is used by @@time_zone variable handling code).
- It will perform lookup in system tables (mysql.time_zone*) if needed.
+ It will perform lookup in system tables (mysql.time_zone*) if needed
+ using tz_tables as list of already opened tables (for info about this
+ list look at tz_load_from_open_tables() description). It won't perform
+ such lookup if no time zone describing tables were found during server
+ start up.
RETURN VALUE
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
@@ -2099,7 +2129,7 @@ str_to_offset(const char *str, uint length, long *offset)
*/
Time_zone *
-my_tz_find(THD *thd, const String * name)
+my_tz_find(const String * name, TABLE_LIST *tz_tables)
{
TZ_NAMES_ENTRY *tmp_tzname;
Time_zone *result_tz= 0;
@@ -2109,6 +2139,8 @@ my_tz_find(THD *thd, const String * name)
DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr() : "NULL"));
+ DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
+
if (!name)
DBUG_RETURN(0);
@@ -2136,8 +2168,10 @@ my_tz_find(THD *thd, const String * name)
(const byte *)name->ptr(),
name->length())))
result_tz= tmp_tzname->tz;
+ else if(time_zone_tables_exist)
+ result_tz= tz_load_from_open_tables(name, tz_tables);
else
- result_tz= tz_load_from_db(thd, name);
+ result_tz= 0;
}
VOID(pthread_mutex_unlock(&tz_LOCK));
diff --git a/sql/tztime.h b/sql/tztime.h
index 69ff176326e..aabec260ec7 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -59,7 +59,8 @@ public:
extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM;
-extern Time_zone * my_tz_find(THD *thd, const String *name);
+extern TABLE_LIST * my_tz_get_table_list(THD *thd);
+extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();