summaryrefslogtreecommitdiff
path: root/sql/tztime.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/tztime.cc')
-rw-r--r--sql/tztime.cc253
1 files changed, 186 insertions, 67 deletions
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 9af33526c98..bd8e43075c4 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -880,7 +880,8 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
0 in case of error.
*/
static my_time_t
-TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, bool *in_dst_time_gap)
+TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
+ my_bool *in_dst_time_gap)
{
my_time_t local_t;
uint saved_seconds;
@@ -1006,8 +1007,9 @@ static const String tz_SYSTEM_name("SYSTEM", 6, &my_charset_latin1);
class Time_zone_system : public Time_zone
{
public:
+ Time_zone_system() {} /* Remove gcc warning */
virtual my_time_t TIME_to_gmt_sec(const TIME *t,
- bool *in_dst_time_gap) const;
+ my_bool *in_dst_time_gap) const;
virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
@@ -1039,7 +1041,7 @@ public:
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_system::TIME_to_gmt_sec(const TIME *t, bool *in_dst_time_gap) const
+Time_zone_system::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
{
long not_used;
return my_system_gmt_sec(t, &not_used, in_dst_time_gap);
@@ -1099,8 +1101,9 @@ Time_zone_system::get_name() const
class Time_zone_utc : public Time_zone
{
public:
+ Time_zone_utc() {} /* Remove gcc warning */
virtual my_time_t TIME_to_gmt_sec(const TIME *t,
- bool *in_dst_time_gap) const;
+ my_bool *in_dst_time_gap) const;
virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
@@ -1126,7 +1129,7 @@ public:
0
*/
my_time_t
-Time_zone_utc::TIME_to_gmt_sec(const TIME *t, bool *in_dst_time_gap) const
+Time_zone_utc::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
{
/* Should be never called */
DBUG_ASSERT(0);
@@ -1189,7 +1192,7 @@ class Time_zone_db : public Time_zone
public:
Time_zone_db(TIME_ZONE_INFO *tz_info_arg, const String * tz_name_arg);
virtual my_time_t TIME_to_gmt_sec(const TIME *t,
- bool *in_dst_time_gap) const;
+ my_bool *in_dst_time_gap) const;
virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
private:
@@ -1238,7 +1241,7 @@ Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_db::TIME_to_gmt_sec(const TIME *t, bool *in_dst_time_gap) const
+Time_zone_db::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
{
return ::TIME_to_gmt_sec(t, tz_info, in_dst_time_gap);
}
@@ -1285,7 +1288,7 @@ class Time_zone_offset : public Time_zone
public:
Time_zone_offset(long tz_offset_arg);
virtual my_time_t TIME_to_gmt_sec(const TIME *t,
- bool *in_dst_time_gap) const;
+ my_bool *in_dst_time_gap) const;
virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
/*
@@ -1337,7 +1340,7 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_offset::TIME_to_gmt_sec(const TIME *t, bool *in_dst_time_gap) const
+Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
{
my_time_t local_t;
@@ -1428,11 +1431,30 @@ static LS_INFO *tz_lsis= 0;
static bool time_zone_tables_exist= 1;
-typedef struct st_tz_names_entry: public Sql_alloc
+/*
+ Names of tables (with their lengths) that are needed
+ for dynamical loading of time zone descriptions.
+*/
+
+static const LEX_STRING tz_tables_names[MY_TZ_TABLES_COUNT]=
+{
+ {(char *) STRING_WITH_LEN("time_zone_name")},
+ {(char *) STRING_WITH_LEN("time_zone")},
+ {(char *) STRING_WITH_LEN("time_zone_transition_type")},
+ {(char *) STRING_WITH_LEN("time_zone_transition")}
+};
+
+/* Name of database to which those tables belong. */
+
+static const LEX_STRING tz_tables_db_name= {(char *) STRING_WITH_LEN("mysql")};
+
+
+class Tz_names_entry: public Sql_alloc
{
+public:
String name;
Time_zone *tz;
-} TZ_NAMES_ENTRY;
+};
/*
@@ -1440,7 +1462,7 @@ typedef struct st_tz_names_entry: public Sql_alloc
they should obey C calling conventions.
*/
-extern "C" byte* my_tz_names_get_key(TZ_NAMES_ENTRY *entry, uint *length,
+extern "C" byte* my_tz_names_get_key(Tz_names_entry *entry, uint *length,
my_bool not_used __attribute__((unused)))
{
*length= entry->name.length();
@@ -1456,48 +1478,78 @@ 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.
+ Prepare table list with time zone related tables from preallocated array
+ and add to global table list.
SYNOPSIS
tz_init_table_list()
- tz_tabs - pointer to preallocated array of 4 TABLE_LIST objects.
+ tz_tabs - pointer to preallocated array of MY_TZ_TABLES_COUNT
+ TABLE_LIST objects
+ global_next_ptr - pointer to variable which points to global_next member
+ of last element of global table list (or list root
+ then list is empty) (in/out).
DESCRIPTION
This function prepares list of TABLE_LIST objects which can be used
- for opening of time zone tables from preallocated array.
+ for opening of time zone tables from preallocated array. It also links
+ this list to the end of global table list (it will read and update
+ accordingly variable pointed by global_next_ptr for this).
*/
-void
-tz_init_table_list(TABLE_LIST *tz_tabs)
+static void
+tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
{
- 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";
+ bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
+
+ for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
+ {
+ tz_tabs[i].alias= tz_tabs[i].table_name= tz_tables_names[i].str;
+ tz_tabs[i].table_name_length= tz_tables_names[i].length;
+ tz_tabs[i].db= tz_tables_db_name.str;
+ tz_tabs[i].db_length= tz_tables_db_name.length;
+ tz_tabs[i].lock_type= TL_READ;
+
+ if (i != MY_TZ_TABLES_COUNT - 1)
+ tz_tabs[i].next_global= tz_tabs[i].next_local= &tz_tabs[i+1];
+ if (i != 0)
+ tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
+ }
+
+ /* Link into global list */
+ tz_tabs[0].prev_global= *global_next_ptr;
+ **global_next_ptr= tz_tabs;
+ /* Update last-global-pointer to point to pointer in last table */
+ *global_next_ptr= &tz_tabs[MY_TZ_TABLES_COUNT-1].next_global;
}
/*
- Create table list with time zone related tables.
+ Fake table list object, pointer to which is returned by
+ my_tz_get_tables_list() as indication of error.
+*/
+TABLE_LIST fake_time_zone_tables_list;
+
+/*
+ Create table list with time zone related tables and add it to the end
+ of global table list.
SYNOPSIS
my_tz_get_table_list()
- thd - current thread object
+ thd - current thread object
+ global_next_ptr - pointer to variable which points to global_next member
+ of last element of global table list (or list root
+ then list is empty) (in/out).
DESCRIPTION
This function creates list of TABLE_LIST objects allocated in thd's
- memroot, which can be used for opening of time zone tables.
+ memroot, which can be used for opening of time zone tables. It will also
+ link this list to the end of global table list (it will read and update
+ accordingly variable pointed by global_next_ptr for this).
NOTE
my_tz_check_n_skip_implicit_tables() function depends on fact that
- elements of list created are allocated as TABLE_LIST[4] array.
+ elements of list created are allocated as TABLE_LIST[MY_TZ_TABLES_COUNT]
+ array.
RETURN VALUES
Returns pointer to first TABLE_LIST object, (could be 0 if time zone
@@ -1505,19 +1557,21 @@ tz_init_table_list(TABLE_LIST *tz_tabs)
*/
TABLE_LIST *
-my_tz_get_table_list(THD *thd)
+my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr)
{
TABLE_LIST *tz_tabs;
+ DBUG_ENTER("my_tz_get_table_list");
if (!time_zone_tables_exist)
- return 0;
+ DBUG_RETURN(0);
- if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) * 4)))
- return &fake_time_zone_tables_list;
+ if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) *
+ MY_TZ_TABLES_COUNT)))
+ DBUG_RETURN(&fake_time_zone_tables_list);
- tz_init_table_list(tz_tabs);
+ tz_init_table_list(tz_tabs, global_next_ptr);
- return tz_tabs;
+ DBUG_RETURN(tz_tabs);
}
@@ -1551,12 +1605,12 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
TABLE_LIST *tables= 0;
- TABLE_LIST tables_buff[5];
+ TABLE_LIST tables_buff[1+MY_TZ_TABLES_COUNT], **last_global_next_ptr;
TABLE *table;
- TZ_NAMES_ENTRY *tmp_tzname;
+ Tz_names_entry *tmp_tzname;
my_bool return_val= 1;
+ char db[]= "mysql";
int res;
- uint counter;
DBUG_ENTER("my_tz_init");
/*
@@ -1564,6 +1618,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
*/
if (!(thd= new THD))
DBUG_RETURN(1);
+ thd->thread_stack= (char*) &thd;
thd->store_globals();
/* Init all memory structures that require explicit destruction */
@@ -1585,12 +1640,12 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
tz_inited= 1;
/* Add 'SYSTEM' time zone to tz_names hash */
- if (!(tmp_tzname= new (&tz_storage) TZ_NAMES_ENTRY()))
+ if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()))
{
sql_print_error("Fatal error: OOM while initializing time zones");
goto end_with_cleanup;
}
- tmp_tzname->name.set("SYSTEM", 6, &my_charset_latin1);
+ tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1);
tmp_tzname->tz= my_tz_SYSTEM;
if (my_hash_insert(&tz_names, (const byte *)tmp_tzname))
{
@@ -1611,19 +1666,20 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
leap seconds shared by all time zones.
*/
- thd->db= my_strdup("mysql",MYF(0));
- thd->db_length= 5; // Safety
+ thd->set_db(db, sizeof(db)-1);
bzero((char*) &tables_buff, sizeof(TABLE_LIST));
- tables_buff[0].alias= tables_buff[0].real_name=
+ tables_buff[0].alias= tables_buff[0].table_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);
+ tables_buff[0].db= db;
+ /*
+ Fill TABLE_LIST for the rest of the time zone describing tables
+ and link it to first one.
+ */
+ last_global_next_ptr= &(tables_buff[0].next_global);
+ tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
- if (open_tables(thd, tables_buff, &counter) ||
- lock_tables(thd, tables_buff, counter))
+ if (simple_open_n_lock_tables(thd, tables_buff))
{
sql_print_warning("Can't open and lock time zone table: %s "
"trying to live without them", thd->net.last_error);
@@ -1779,7 +1835,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
{
TABLE *table= 0;
TIME_ZONE_INFO *tz_info;
- TZ_NAMES_ENTRY *tmp_tzname;
+ Tz_names_entry *tmp_tzname;
Time_zone *return_val= 0;
int res;
uint tzid, ttid;
@@ -1822,8 +1878,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
and it is specifically for this purpose).
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
- table->field[0]->store(tz_name->ptr(), tz_name->length(), &my_charset_latin1);
+ tz_tables= tz_tables->next_local;
+ table->field[0]->store(tz_name->ptr(), tz_name->length(),
+ &my_charset_latin1);
/*
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
@@ -1854,8 +1911,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
using the only index in this table).
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
- table->field[0]->store((longlong)tzid);
+ tz_tables= tz_tables->next_local;
+ table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
@@ -1881,8 +1938,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Right - using special index.
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
- table->field[0]->store((longlong)tzid);
+ tz_tables= tz_tables->next_local;
+ table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
@@ -1954,7 +2011,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
in ascending order by index scan also satisfies us.
*/
table= tz_tables->table;
- table->field[0]->store((longlong)tzid);
+ table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
@@ -2053,7 +2110,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
}
- if (!(tmp_tzname= new (&tz_storage) TZ_NAMES_ENTRY()) ||
+ if (!(tmp_tzname= new (&tz_storage) Tz_names_entry()) ||
!(tmp_tzname->tz= new (&tz_storage) Time_zone_db(tz_info,
&(tmp_tzname->name))) ||
(tmp_tzname->name.set(tz_name_buff, tz_name->length(),
@@ -2200,7 +2257,7 @@ str_to_offset(const char *str, uint length, long *offset)
Time_zone *
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;
long offset;
@@ -2208,7 +2265,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr() : "NULL"));
- DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
+ DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread);
if (!name)
DBUG_RETURN(0);
@@ -2236,11 +2293,11 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
else
{
result_tz= 0;
- if ((tmp_tzname= (TZ_NAMES_ENTRY *)hash_search(&tz_names,
+ if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
(const byte *)name->ptr(),
name->length())))
result_tz= tmp_tzname->tz;
- else if (time_zone_tables_exist)
+ else if (time_zone_tables_exist && tz_tables)
result_tz= tz_load_from_open_tables(name, tz_tables);
}
@@ -2249,6 +2306,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_RETURN(result_tz);
}
+
+/*
+ A more standalone version of my_tz_find(): will open tz tables if needed.
+ This is so far only used by replication, where time zone setting does not
+ happen in the usual query context.
+
+ SYNOPSIS
+ my_tz_find_with_opening_tz_tables()
+ thd - pointer to thread's THD structure
+ name - time zone specification
+
+ DESCRIPTION
+ This function tries to find a time zone which matches the named passed in
+ argument. If it fails, it will open time zone tables and re-try the
+ search.
+ This function is needed for the slave SQL thread, which does not do the
+ addition of time zone tables which is usually done during query parsing
+ (as time zone setting by slave does not happen in mysql_parse() but
+ before). So it needs to open tz tables by itself if needed.
+ See notes of my_tz_find() as they also apply here.
+
+ RETURN VALUE
+ Pointer to corresponding Time_zone object. 0 - in case of bad time zone
+ specification or other error.
+
+*/
+Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
+{
+ Time_zone *tz;
+ DBUG_ENTER("my_tz_find_with_opening_tables");
+ DBUG_ASSERT(thd);
+ DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
+ if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
+ {
+ /*
+ Probably we have not loaded this time zone yet so let us look it up in
+ our time zone tables. Note that if we don't have tz tables on this
+ slave, we don't even try.
+ */
+ TABLE_LIST tables[MY_TZ_TABLES_COUNT];
+ TABLE_LIST *dummy;
+ TABLE_LIST **dummyp= &dummy;
+ tz_init_table_list(tables, &dummyp);
+ if (simple_open_n_lock_tables(thd, tables))
+ DBUG_RETURN(0);
+ tz= my_tz_find(name, tables);
+ /* We need to close tables _now_ to not pollute coming query */
+ close_thread_tables(thd);
+ }
+ DBUG_RETURN(tz);
+}
+
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
@@ -2531,8 +2640,6 @@ main(int argc, char **argv)
time_t t, t1, t2;
char fullname[FN_REFLEN+1];
char *str_end;
- long not_used;
- bool not_used_2;
MEM_ROOT tz_storage;
MY_INIT(argv[0]);
@@ -2642,14 +2749,21 @@ main(int argc, char **argv)
dates.
*/
for (time_tmp.year= 1980; time_tmp.year < 2010; time_tmp.year++)
+ {
for (time_tmp.month= 1; time_tmp.month < 13; time_tmp.month++)
+ {
for (time_tmp.day= 1;
time_tmp.day < mon_lengths[isleap(time_tmp.year)][time_tmp.month-1];
time_tmp.day++)
+ {
for (time_tmp.hour= 0; time_tmp.hour < 24; time_tmp.hour++)
+ {
for (time_tmp.minute= 0; time_tmp.minute < 60; time_tmp.minute+= 5)
+ {
for (time_tmp.second=0; time_tmp.second<60; time_tmp.second+=25)
{
+ long not_used;
+ my_bool not_used_2;
t= (time_t)my_system_gmt_sec(&time_tmp, &not_used, &not_used_2);
t1= (time_t)TIME_to_gmt_sec(&time_tmp, &tz_info, &not_used_2);
if (t != t1)
@@ -2681,6 +2795,11 @@ main(int argc, char **argv)
return 1;
}
}
+ }
+ }
+ }
+ }
+ }
printf("TIME_to_gmt_sec = my_system_gmt_sec for test range\n");