mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +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');
|
select convert_tz( NULL, 'MET', 'UTC');
|
||||||
convert_tz( NULL, 'MET', 'UTC')
|
convert_tz( NULL, 'MET', 'UTC')
|
||||||
NULL
|
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', 'SomeNotExistingTimeZone');
|
||||||
select convert_tz('2003-12-31 04:00:00', 'MET', NULL);
|
select convert_tz('2003-12-31 04:00:00', 'MET', NULL);
|
||||||
select convert_tz( NULL, 'MET', 'UTC');
|
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
|
then
|
||||||
i_tzn="$i_tzn INSERT INTO time_zone_name (Name, Time_Zone_id) VALUES"
|
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 ('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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -327,7 +328,7 @@ then
|
|||||||
if test "$1" = "test"
|
if test "$1" = "test"
|
||||||
then
|
then
|
||||||
i_tz="$i_tz INSERT INTO time_zone (Time_zone_id, Use_leap_seconds)"
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -546,7 +547,8 @@ then
|
|||||||
i_tzt="$i_tzt ,(4, 2045689222, 8) ,(4, 2058390022, 9)"
|
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, 2077138822, 8) ,(4, 2090444422, 9)"
|
||||||
i_tzt="$i_tzt ,(4, 2108588422, 8) ,(4, 2121894022, 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
|
||||||
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, 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, 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, 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -89,11 +89,6 @@ Item *create_func_conv(Item* a, Item *b, Item *c)
|
|||||||
return new Item_func_conv(a,b,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)
|
Item *create_func_cos(Item* a)
|
||||||
{
|
{
|
||||||
return new Item_func_cos(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_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
|
||||||
Item *create_func_connection_id(void);
|
Item *create_func_connection_id(void);
|
||||||
Item *create_func_conv(Item* a, Item *b, Item *c);
|
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_cos(Item* a);
|
||||||
Item *create_func_cot(Item* a);
|
Item *create_func_cot(Item* a);
|
||||||
Item *create_func_crc32(Item* a);
|
Item *create_func_crc32(Item* a);
|
||||||
|
@ -1648,19 +1648,29 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
|
|||||||
|
|
||||||
|
|
||||||
void Item_func_convert_tz::fix_length_and_dec()
|
void Item_func_convert_tz::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
String str;
|
|
||||||
|
|
||||||
thd= current_thd;
|
|
||||||
collation.set(&my_charset_bin);
|
collation.set(&my_charset_bin);
|
||||||
decimals= 0;
|
decimals= 0;
|
||||||
max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
|
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())
|
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())
|
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;
|
String str;
|
||||||
|
|
||||||
if (!args[1]->const_item())
|
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())
|
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))
|
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;
|
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
|
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;
|
Time_zone *from_tz, *to_tz;
|
||||||
public:
|
public:
|
||||||
Item_func_convert_tz(Item *a, Item *b, Item *c):
|
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(); }
|
double val() { return (double) val_int(); }
|
||||||
String *val_str(String *str);
|
String *val_str(String *str);
|
||||||
const char *func_name() const { return "convert_tz"; }
|
const char *func_name() const { return "convert_tz"; }
|
||||||
|
bool fix_fields(THD *, struct st_table_list *, Item **);
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
bool get_date(TIME *res, uint fuzzy_date);
|
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)},
|
{ "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)},
|
{ "CONTAINS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_contains)},
|
||||||
{ "CONV", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
|
{ "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)},
|
{ "COUNT", SYM(COUNT_SYM)},
|
||||||
{ "COS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
|
{ "COS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
|
||||||
{ "COT", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
|
{ "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_result *result, SELECT_LEX_UNIT *unit,
|
||||||
SELECT_LEX *select_lex);
|
SELECT_LEX *select_lex);
|
||||||
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
|
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,
|
int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
|
||||||
select_result *result);
|
select_result *result);
|
||||||
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
|
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
|
||||||
|
@ -2372,8 +2372,9 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#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");
|
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
|
||||||
return 1;
|
return 1;
|
||||||
@ -2418,7 +2419,8 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
|
|||||||
if (default_tz_name)
|
if (default_tz_name)
|
||||||
{
|
{
|
||||||
String str(default_tz_name, &my_charset_latin1);
|
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
|
else
|
||||||
global_system_variables.time_zone= my_tz_SYSTEM;
|
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_charset_system;
|
||||||
extern sys_var_str sys_init_connect;
|
extern sys_var_str sys_init_connect;
|
||||||
extern sys_var_str sys_init_slave;
|
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);
|
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
|
||||||
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
|
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
|
||||||
NAMED_LIST **found);
|
NAMED_LIST **found);
|
||||||
|
@ -1670,7 +1670,22 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
|||||||
uint counter;
|
uint counter;
|
||||||
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
|
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
|
||||||
DBUG_RETURN(-1); /* purecov: inspected */
|
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));
|
DBUG_RETURN(mysql_handle_derived(thd->lex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,16 @@
|
|||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
#include <hash.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 */
|
/* Macros to look like lex */
|
||||||
|
|
||||||
#define yyGet() *(lex->ptr++)
|
#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)
|
TABLE_LIST **result_arg)
|
||||||
{
|
{
|
||||||
*result_arg= 0;
|
*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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +633,12 @@ typedef struct st_lex
|
|||||||
bool prepared_stmt_code_is_varref;
|
bool prepared_stmt_code_is_varref;
|
||||||
/* Names of user variables holding parameters (in EXECUTE) */
|
/* Names of user variables holding parameters (in EXECUTE) */
|
||||||
List<LEX_STRING> prepared_stmt_params;
|
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() {}
|
st_lex() {}
|
||||||
inline void uncacheable(uint8 cause)
|
inline void uncacheable(uint8 cause)
|
||||||
{
|
{
|
||||||
@ -661,6 +667,7 @@ typedef struct st_lex
|
|||||||
TABLE_LIST *local_first);
|
TABLE_LIST *local_first);
|
||||||
} LEX;
|
} LEX;
|
||||||
|
|
||||||
|
extern TABLE_LIST fake_time_zone_tables_list;
|
||||||
|
|
||||||
void lex_init(void);
|
void lex_init(void);
|
||||||
void lex_free(void);
|
void lex_free(void);
|
||||||
|
@ -1897,7 +1897,8 @@ mysql_execute_command(THD *thd)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* !HAVE_REPLICATION */
|
#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))
|
lex->unit.create_total_list(thd, lex, &tables))
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
@ -3875,6 +3876,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length)
|
|||||||
lex->lock_option= TL_READ;
|
lex->lock_option= TL_READ;
|
||||||
lex->found_colon= 0;
|
lex->found_colon= 0;
|
||||||
lex->safe_to_cache_query= 1;
|
lex->safe_to_cache_query= 1;
|
||||||
|
lex->time_zone_tables_used= 0;
|
||||||
lex_start(thd, buf, length);
|
lex_start(thd, buf, length);
|
||||||
thd->select_number= lex->select_lex.select_number= 1;
|
thd->select_number= lex->select_lex.select_number= 1;
|
||||||
thd->free_list= 0;
|
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",
|
DBUG_PRINT("enter",("command: %d, param_count: %ld",
|
||||||
sql_command, stmt->param_count));
|
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))
|
lex->unit.create_total_list(thd, lex, &tables))
|
||||||
DBUG_RETURN(1);
|
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
|
Function to setup clauses without sum functions
|
||||||
*/
|
*/
|
||||||
|
@ -463,6 +463,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
|||||||
%token CASE_SYM
|
%token CASE_SYM
|
||||||
%token CONCAT
|
%token CONCAT
|
||||||
%token CONCAT_WS
|
%token CONCAT_WS
|
||||||
|
%token CONVERT_TZ_SYM
|
||||||
%token CURDATE
|
%token CURDATE
|
||||||
%token CURTIME
|
%token CURTIME
|
||||||
%token DATABASE
|
%token DATABASE
|
||||||
@ -2825,6 +2826,11 @@ simple_expr:
|
|||||||
{ $$= new Item_func_concat(* $3); }
|
{ $$= new Item_func_concat(* $3); }
|
||||||
| CONCAT_WS '(' expr ',' expr_list ')'
|
| CONCAT_WS '(' expr ',' expr_list ')'
|
||||||
{ $$= new Item_func_concat_ws($3, *$5); }
|
{ $$= 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
|
| CURDATE optional_braces
|
||||||
{ $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; }
|
{ $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; }
|
||||||
| CURTIME optional_braces
|
| CURTIME optional_braces
|
||||||
@ -5308,6 +5314,12 @@ internal_variable_name:
|
|||||||
$$.var= tmp;
|
$$.var= tmp;
|
||||||
$$.base_name.str=0;
|
$$.base_name.str=0;
|
||||||
$$.base_name.length=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
|
| ident '.' ident
|
||||||
{
|
{
|
||||||
|
304
sql/tztime.cc
304
sql/tztime.cc
@ -1359,6 +1359,13 @@ static bool tz_inited= 0;
|
|||||||
static uint tz_leapcnt= 0;
|
static uint tz_leapcnt= 0;
|
||||||
static LS_INFO *tz_lsis= 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
|
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.
|
Initialize time zone support infrastructure.
|
||||||
|
|
||||||
@ -1399,13 +1468,13 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
|
|||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
This function will init memory structures needed for time zone support,
|
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
|
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
|
mysql.time_zone* tables and load information about default time zone and
|
||||||
will be shared among all time zones loaded. It will also try to load
|
information which further will be shared among all time zones loaded.
|
||||||
information about default time zone. If system tables with time zone
|
If system tables with time zone descriptions don't exist it won't fail
|
||||||
descriptions don't exist it won't fail (unless default_tzname is time zone
|
(unless default_tzname is time zone from tables). If bootstrap parameter
|
||||||
from tables). If bootstrap parameter is true then this routine assumes that
|
is true then this routine assumes that we are in bootstrap mode and won't
|
||||||
we are in bootstrap mode and won't load time zone descriptions unless someone
|
load time zone descriptions unless someone specifies default time zone
|
||||||
specifies default time zone which is supposedly stored in those tables.
|
which is supposedly stored in those tables.
|
||||||
It'll also set default time zone if it is specified.
|
It'll also set default time zone if it is specified.
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
@ -1416,14 +1485,13 @@ my_bool
|
|||||||
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
||||||
{
|
{
|
||||||
THD *thd;
|
THD *thd;
|
||||||
TABLE_LIST tables;
|
TABLE_LIST *tables= 0;
|
||||||
|
TABLE_LIST tables_buff[5];
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
TABLE *lock_ptr;
|
|
||||||
MYSQL_LOCK *lock;
|
|
||||||
TZ_NAMES_ENTRY *tmp_tzname;
|
TZ_NAMES_ENTRY *tmp_tzname;
|
||||||
my_bool return_val= 1;
|
my_bool return_val= 1;
|
||||||
int res;
|
int res;
|
||||||
uint not_used;
|
uint counter;
|
||||||
DBUG_ENTER("my_tz_init");
|
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 (bootstrap)
|
||||||
{
|
{
|
||||||
/* If we are in bootstrap mode we should not load time zone tables */
|
/* 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;
|
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= my_strdup("mysql",MYF(0));
|
||||||
thd->db_length= 5; // Safety
|
thd->db_length= 5; // Safety
|
||||||
bzero((char*) &tables,sizeof(tables));
|
bzero((char*) &tables_buff, sizeof(TABLE_LIST));
|
||||||
tables.alias= tables.real_name= (char*)"time_zone_leap_second";
|
tables_buff[0].alias= tables_buff[0].real_name=
|
||||||
tables.lock_type= TL_READ;
|
(char*)"time_zone_leap_second";
|
||||||
tables.db= thd->db;
|
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);
|
"trying to live without them", thd->net.last_error);
|
||||||
/* We will try emulate that everything is ok */
|
/* We will try emulate that everything is ok */
|
||||||
return_val= 0;
|
return_val= time_zone_tables_exist= 0;
|
||||||
goto end_with_setting_default_tz;
|
goto end_with_setting_default_tz;
|
||||||
}
|
}
|
||||||
|
tables= tables_buff + 1;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Now we are going to load leap seconds descriptions that are shared
|
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 "
|
sql_print_error("Fatal error: Out of memory while loading "
|
||||||
"mysql.time_zone_leap_second table");
|
"mysql.time_zone_leap_second table");
|
||||||
goto end_with_unlock;
|
goto end_with_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
table= tables.table;
|
table= tables_buff[0].table;
|
||||||
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);
|
||||||
tz_leapcnt= 0;
|
tz_leapcnt= 0;
|
||||||
|
|
||||||
res= table->file->index_first(table->record[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"
|
sql_print_error("Fatal error: While loading mysql.time_zone_leap_second"
|
||||||
" table: too much leaps");
|
" table: too much leaps");
|
||||||
table->file->ha_index_end();
|
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();
|
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]);
|
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)
|
if (res != HA_ERR_END_OF_FILE)
|
||||||
{
|
{
|
||||||
sql_print_error("Fatal error: Error while loading "
|
sql_print_error("Fatal error: Error while loading "
|
||||||
"mysql.time_zone_leap_second table");
|
"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;
|
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:
|
end_with_setting_default_tz:
|
||||||
/* If not an error and have default time zone try to load it */
|
/* If we have default time zone try to load it */
|
||||||
if (!return_val && default_tzname)
|
if (default_tzname)
|
||||||
{
|
{
|
||||||
String tzname(default_tzname, &my_charset_latin1);
|
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'",
|
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
|
||||||
default_tzname);
|
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:
|
end_with_cleanup:
|
||||||
|
|
||||||
/* if there were error free time zone describing structs */
|
/* if there were error free time zone describing structs */
|
||||||
@ -1625,29 +1692,27 @@ void my_tz_free()
|
|||||||
Load time zone description from system tables.
|
Load time zone description from system tables.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
tz_load_from_db()
|
tz_load_from_open_tables()
|
||||||
thd - current thread object
|
tz_name - name of time zone that should be loaded.
|
||||||
tz_name - name of time zone that should be loaded.
|
tz_tables - list of tables from which time zone description
|
||||||
|
should be loaded
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
This function will try to open system tables describing time zones
|
This function will try to load information about time zone specified
|
||||||
and to load information about time zone specified. It will also update
|
from the list of the already opened and locked tables (first table in
|
||||||
information in hash used for time zones lookup.
|
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
|
RETURN VALUES
|
||||||
Returns pointer to newly created Time_zone object or 0 in case of error.
|
Returns pointer to newly created Time_zone object or 0 in case of error.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static Time_zone*
|
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 *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;
|
TIME_ZONE_INFO *tz_info;
|
||||||
TZ_NAMES_ENTRY *tmp_tzname;
|
TZ_NAMES_ENTRY *tmp_tzname;
|
||||||
Time_zone *return_val= 0;
|
Time_zone *return_val= 0;
|
||||||
@ -1667,9 +1732,8 @@ tz_load_from_db(THD *thd, const String *tz_name)
|
|||||||
#ifdef ABBR_ARE_USED
|
#ifdef ABBR_ARE_USED
|
||||||
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
|
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
|
||||||
#endif
|
#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 */
|
/* 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());
|
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
|
Let us find out time zone id by its name (there is only one index
|
||||||
and it is specifically for this purpose).
|
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->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,
|
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
|
||||||
0, HA_READ_KEY_EXACT))
|
0, HA_READ_KEY_EXACT))
|
||||||
{
|
{
|
||||||
sql_print_error("Error: Can't find description of time zone.");
|
sql_print_error("Error: Can't find description of time zone.");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
tzid= (uint)table->field[1]->val_int();
|
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
|
Now we need to lookup record in mysql.time_zone table in order to
|
||||||
understand whenever this timezone uses leap seconds (again we are
|
understand whenever this timezone uses leap seconds (again we are
|
||||||
using the only index in this table).
|
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->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,
|
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
|
||||||
0, HA_READ_KEY_EXACT))
|
0, HA_READ_KEY_EXACT))
|
||||||
{
|
{
|
||||||
sql_print_error("Error: Can't find description of time zone.");
|
sql_print_error("Error: Can't find description of time zone.");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If Uses_leap_seconds == 'Y' */
|
/* If Uses_leap_seconds == 'Y' */
|
||||||
@ -1769,7 +1802,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
|
|||||||
tz_info->lsis= tz_lsis;
|
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
|
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?
|
only for our time zone guess what are we doing?
|
||||||
Right - using special index.
|
Right - using special index.
|
||||||
*/
|
*/
|
||||||
table= tables[3].table;
|
table= tz_tables->table;
|
||||||
|
tz_tables= tz_tables->next;
|
||||||
table->field[0]->store((longlong)tzid);
|
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 ???
|
// FIXME Is there any better approach than explicitly specifying 4 ???
|
||||||
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
|
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 "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition_type table: too big "
|
"mysql.time_zone_transition_type table: too big "
|
||||||
"transition type id");
|
"transition type id");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
|
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 "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition_type table: not enough "
|
"mysql.time_zone_transition_type table: not enough "
|
||||||
"room for abbreviations");
|
"room for abbreviations");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
ttis[ttid].tt_abbrind= tz_info->charcnt;
|
ttis[ttid].tt_abbrind= tz_info->charcnt;
|
||||||
memcpy(chars + tz_info->charcnt, abbr.ptr(), abbr.length());
|
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 "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition_type table");
|
"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
|
mysql.time_zone_transition table. Here we additionaly need records
|
||||||
in ascending order by index scan also satisfies us.
|
in ascending order by index scan also satisfies us.
|
||||||
*/
|
*/
|
||||||
table= tables[2].table;
|
table= tz_tables->table;
|
||||||
table->field[0]->store((longlong)tzid);
|
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 ???
|
// FIXME Is there any better approach than explicitly specifying 4 ???
|
||||||
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
|
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 "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition table: "
|
"mysql.time_zone_transition table: "
|
||||||
"too much transitions");
|
"too much transitions");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
if (ttid + 1 > tz_info->typecnt)
|
if (ttid + 1 > tz_info->typecnt)
|
||||||
{
|
{
|
||||||
sql_print_error("Error while loading time zone description from "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition table: "
|
"mysql.time_zone_transition table: "
|
||||||
"bad transition type id");
|
"bad transition type id");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ats[tz_info->timecnt]= ttime;
|
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 "
|
sql_print_error("Error while loading time zone description from "
|
||||||
"mysql.time_zone_transition table");
|
"mysql.time_zone_transition table");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
table->file->ha_index_end();
|
(void)table->file->ha_index_end();
|
||||||
table= 0;
|
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 "
|
sql_print_error("Error: Out of memory while loading time zone "
|
||||||
"description");
|
"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)
|
if (tz_info->typecnt < 1)
|
||||||
{
|
{
|
||||||
sql_print_error("Error: loading time zone without transition types");
|
sql_print_error("Error: loading time zone without transition types");
|
||||||
goto end_with_unlock;
|
goto end;
|
||||||
}
|
}
|
||||||
if (prepare_tz_info(tz_info, &tz_storage))
|
if (prepare_tz_info(tz_info, &tz_storage))
|
||||||
{
|
{
|
||||||
sql_print_error("Error: Unable to build mktime map for time zone");
|
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)))
|
my_hash_insert(&tz_names, (const byte *)tmp_tzname)))
|
||||||
{
|
{
|
||||||
sql_print_error("Error: Out of memory while loading time zone");
|
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;
|
return_val= tmp_tzname->tz;
|
||||||
|
|
||||||
end_with_unlock:
|
end:
|
||||||
|
|
||||||
if (table)
|
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);
|
DBUG_RETURN(return_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2068,8 +2094,8 @@ str_to_offset(const char *str, uint length, long *offset)
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
my_tz_find()
|
my_tz_find()
|
||||||
thd - current thread
|
|
||||||
name - time zone specification
|
name - time zone specification
|
||||||
|
tz_tables - list of opened'n'locked time zone describing tables
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
This function checks if name is one of time zones described in db,
|
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
|
values as parameter without additional external check and this property
|
||||||
is used by @@time_zone variable handling code).
|
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
|
RETURN VALUE
|
||||||
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
|
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 *
|
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;
|
TZ_NAMES_ENTRY *tmp_tzname;
|
||||||
Time_zone *result_tz= 0;
|
Time_zone *result_tz= 0;
|
||||||
@ -2109,6 +2139,8 @@ my_tz_find(THD *thd, const String * name)
|
|||||||
DBUG_PRINT("enter", ("time zone name='%s'",
|
DBUG_PRINT("enter", ("time zone name='%s'",
|
||||||
name ? ((String *)name)->c_ptr() : "NULL"));
|
name ? ((String *)name)->c_ptr() : "NULL"));
|
||||||
|
|
||||||
|
DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
@ -2136,8 +2168,10 @@ my_tz_find(THD *thd, const String * name)
|
|||||||
(const byte *)name->ptr(),
|
(const byte *)name->ptr(),
|
||||||
name->length())))
|
name->length())))
|
||||||
result_tz= tmp_tzname->tz;
|
result_tz= tmp_tzname->tz;
|
||||||
|
else if(time_zone_tables_exist)
|
||||||
|
result_tz= tz_load_from_open_tables(name, tz_tables);
|
||||||
else
|
else
|
||||||
result_tz= tz_load_from_db(thd, name);
|
result_tz= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID(pthread_mutex_unlock(&tz_LOCK));
|
VOID(pthread_mutex_unlock(&tz_LOCK));
|
||||||
|
@ -59,7 +59,8 @@ public:
|
|||||||
|
|
||||||
extern Time_zone * my_tz_UTC;
|
extern Time_zone * my_tz_UTC;
|
||||||
extern Time_zone * my_tz_SYSTEM;
|
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 my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
|
||||||
extern void my_tz_free();
|
extern void my_tz_free();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user