mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fix for bug #4508 "CONVERT_TZ() function with new time zone as param crashes server".
Instead of trying to open time zone tables during calculation of CONVERT_TZ() function or setting of @@time_zone variable we should open and lock them with the rest of statement's table (so we should add them to global table list) and after that use such pre-opened tables for loading info about time zones.
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -1649,18 +1649,28 @@ 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))
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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)},
|
||||
|
@ -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,
|
||||
|
@ -2373,7 +2373,8 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
|
||||
}
|
||||
#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;
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
{
|
||||
|
302
sql/tztime.cc
302
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
|
||||
{
|
||||
@ -1387,6 +1394,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.
|
||||
|
||||
@ -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;
|
||||
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, ¬_used))
|
||||
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_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 */
|
||||
@ -1689,77 +1753,46 @@ 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, ¬_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();
|
||||
(void)table->file->ha_index_end();
|
||||
|
||||
mysql_unlock_tables(thd, lock);
|
||||
|
||||
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));
|
||||
|
@ -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();
|
||||
|
||||
|
Reference in New Issue
Block a user