Commit 38407743 authored by unknown's avatar unknown

Added code to mysqldump to dump timed events when instructed to do so, with

the '-E' or '--events' flag.  (Closes Bug#16853 and Bug#17714.)


WARNING:

At present, these tests fail due to b*g number 18078.


client/mysqldump.c:
  Added code to dump events, when asked to do so via the --events parameter.
  
  Also cleaned up some surrounding code.
mysql-test/r/mysqldump.result:
  Added a test to create an event, dump it, restore it, add more events, dump
  all of them, and restore all of them.
mysql-test/t/mysqldump.test:
  Added a test to create an event, dump it, restore it, add more events, dump
  all of them, and restore all of them.
sql/event_timed.cc:
  No longer qualify SHOW CREATE EVENT names with the database name.
BitKeeper/etc/ignore:
  Removing accidentally 'ignored' bogus file entry.
parent 39e4157f
...@@ -95,6 +95,7 @@ static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, ...@@ -95,6 +95,7 @@ static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1,
opt_complete_insert= 0, opt_drop_database= 0, opt_complete_insert= 0, opt_drop_database= 0,
opt_replace_into= 0, opt_replace_into= 0,
opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1, opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1,
opt_events= 0,
opt_alltspcs=0; opt_alltspcs=0;
static ulong opt_max_allowed_packet, opt_net_buffer_length; static ulong opt_max_allowed_packet, opt_net_buffer_length;
static MYSQL mysql_connection,*sock=0; static MYSQL mysql_connection,*sock=0;
...@@ -231,6 +232,9 @@ static struct my_option my_long_options[] = ...@@ -231,6 +232,9 @@ static struct my_option my_long_options[] =
{"disable-keys", 'K', {"disable-keys", 'K',
"'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys, "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys,
(gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"events", 'E', "Dump events.",
(gptr*) &opt_events, (gptr*) &opt_events, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"extended-insert", 'e', {"extended-insert", 'e',
"Allows utilization of the new, much faster INSERT syntax.", "Allows utilization of the new, much faster INSERT syntax.",
(gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG, (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG,
...@@ -1238,9 +1242,136 @@ static void print_xml_row(FILE *xml_file, const char *row_name, ...@@ -1238,9 +1242,136 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
check_io(xml_file); check_io(xml_file);
} }
/*
create_delimiter
Generate a new (null-terminated) string that does not exist in query
and is therefore suitable for use as a query delimiter. Store this
delimiter in delimiter_buff .
This is quite simple in that it doesn't even try to parse statements as an
interpreter would. It merely returns a string that is not in the query, which
is much more than adequate for constructing a delimiter.
RETURN
ptr to the delimiter on Success
NULL on Failure
*/
static char *create_delimiter(char *query, char *delimiter_buff,
int delimiter_max_size)
{
int proposed_length;
char *presence;
delimiter_buff[0]= ';'; /* start with one semicolon, and */
for (proposed_length= 2; proposed_length < delimiter_max_size;
delimiter_max_size++) {
delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */
delimiter_buff[proposed_length]= '\0';
presence = strstr(query, delimiter_buff);
if (presence == NULL) { /* the proposed delimiter is not in the query. */
return delimiter_buff;
}
}
return NULL; /* but if we run out of space, return nothing at all. */
}
/*
dump_events_for_db
-- retrieves list of events for a given db, and prints out
the CREATE EVENT statement into the output (the dump).
RETURN
0 Success
1 Error
*/
static uint dump_events_for_db(char *db)
{
char query_buff[QUERY_LENGTH];
char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
char *event_name;
char delimiter[QUERY_LENGTH], *delimit_test;
FILE *sql_file= md_result_file;
MYSQL_RES *event_res, *event_list_res;
MYSQL_ROW row, event_list_row;
DBUG_ENTER("dump_events_for_db");
DBUG_PRINT("enter", ("db: '%s'", db));
mysql_real_escape_string(sock, db_name_buff, db, strlen(db));
/* nice comments */
if (opt_comments)
fprintf(sql_file, "\n--\n-- Dumping events for database '%s'\n--\n", db);
/*
not using "mysql_query_with_error_report" because we may have not
enough privileges to lock mysql.events.
*/
if (lock_tables)
mysql_query(sock, "LOCK TABLES mysql.event READ");
if (mysql_query_with_error_report(sock, &event_list_res, "show events"))
{
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
}
strcpy(delimiter, ";");
if (mysql_num_rows(event_list_res) > 0)
{
while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
{
event_name= quote_name(event_list_row[1], name_buff, 0);
DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff));
my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s",
event_name);
if (mysql_query_with_error_report(sock, &event_res, query_buff))
DBUG_RETURN(1);
while ((row= mysql_fetch_row(event_res)) != NULL)
{
/*
if the user has EXECUTE privilege he can see event names, but not the
event body!
*/
if (strlen(row[2]) != 0)
{
if (opt_drop)
fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n",
event_name, delimiter);
delimit_test= create_delimiter(row[2], delimiter, sizeof(delimiter));
if (delimit_test == NULL) {
fprintf(stderr, "%s: Warning: Can't dump event '%s'\n",
event_name, my_progname);
DBUG_RETURN(1);
}
fprintf(sql_file, "DELIMITER %s\n", delimiter);
fprintf(sql_file, "/*!50106 %s */ %s\n", row[2], delimiter);
}
} /* end of event printing */
} /* end of list of events */
fprintf(sql_file, "DELIMITER ;\n");
mysql_free_result(event_res);
}
mysql_free_result(event_list_res);
if (lock_tables)
VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"));
DBUG_RETURN(0);
}
/* /*
dump_routines_for_db dump_routines_for_db
-- retrievs list of routines for a given db, and prints out -- retrieves list of routines for a given db, and prints out
the CREATE PROCEDURE definition into the output (the dump). the CREATE PROCEDURE definition into the output (the dump).
This function has logic to print the appropriate syntax depending on whether This function has logic to print the appropriate syntax depending on whether
...@@ -1253,7 +1384,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name, ...@@ -1253,7 +1384,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
static uint dump_routines_for_db(char *db) static uint dump_routines_for_db(char *db)
{ {
char query_buff[512]; char query_buff[QUERY_LENGTH];
const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
char *routine_name; char *routine_name;
...@@ -1294,9 +1425,9 @@ static uint dump_routines_for_db(char *db) ...@@ -1294,9 +1425,9 @@ static uint dump_routines_for_db(char *db)
while ((routine_list_row= mysql_fetch_row(routine_list_res))) while ((routine_list_row= mysql_fetch_row(routine_list_res)))
{ {
routine_name= quote_name(routine_list_row[1], name_buff, 0);
DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i], DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
name_buff)); name_buff));
routine_name= quote_name(routine_list_row[1], name_buff, 0);
my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s", my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
routine_type[i], routine_name); routine_type[i], routine_name);
...@@ -1364,7 +1495,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, ...@@ -1364,7 +1495,7 @@ static uint get_table_structure(char *table, char *db, char *table_type,
char *result_table, *opt_quoted_table; char *result_table, *opt_quoted_table;
const char *insert_option; const char *insert_option;
char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
char table_buff2[NAME_LEN*2+3], query_buff[512]; char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
FILE *sql_file = md_result_file; FILE *sql_file = md_result_file;
int len; int len;
MYSQL_RES *result; MYSQL_RES *result;
...@@ -1840,7 +1971,7 @@ static void dump_triggers_for_table (char *table, char *db) ...@@ -1840,7 +1971,7 @@ static void dump_triggers_for_table (char *table, char *db)
{ {
char *result_table; char *result_table;
char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3];
char query_buff[512]; char query_buff[QUERY_LENGTH];
uint old_opt_compatible_mode=opt_compatible_mode; uint old_opt_compatible_mode=opt_compatible_mode;
FILE *sql_file = md_result_file; FILE *sql_file = md_result_file;
MYSQL_RES *result; MYSQL_RES *result;
...@@ -2500,7 +2631,6 @@ static int dump_all_tablespaces() ...@@ -2500,7 +2631,6 @@ static int dump_all_tablespaces()
{ {
MYSQL_ROW row; MYSQL_ROW row;
MYSQL_RES *tableres; MYSQL_RES *tableres;
int result=0;
char buf[FN_REFLEN]; char buf[FN_REFLEN];
int first; int first;
...@@ -2798,6 +2928,12 @@ static int dump_all_tables_in_db(char *database) ...@@ -2798,6 +2928,12 @@ static int dump_all_tables_in_db(char *database)
dump_triggers_for_table(table, database); dump_triggers_for_table(table, database);
} }
} }
if (opt_events && !opt_xml &&
mysql_get_server_version(sock) >= 50106)
{
DBUG_PRINT("info", ("Dumping events for database %s", database));
dump_events_for_db(database);
}
if (opt_routines && !opt_xml && if (opt_routines && !opt_xml &&
mysql_get_server_version(sock) >= 50009) mysql_get_server_version(sock) >= 50009)
{ {
...@@ -3008,6 +3144,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables) ...@@ -3008,6 +3144,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
get_view_structure(table_name, db); get_view_structure(table_name, db);
} }
} }
if (opt_events && !opt_xml &&
mysql_get_server_version(sock) >= 50106)
{
DBUG_PRINT("info", ("Dumping events for database %s", db));
dump_events_for_db(db);
}
/* obtain dump of routines (procs/functions) */ /* obtain dump of routines (procs/functions) */
if (opt_routines && !opt_xml && if (opt_routines && !opt_xml &&
mysql_get_server_version(sock) >= 50009) mysql_get_server_version(sock) >= 50009)
......
...@@ -2907,3 +2907,40 @@ mysql-import: Error: 1146, Table 'test.words' doesn't exist, when using table: w ...@@ -2907,3 +2907,40 @@ mysql-import: Error: 1146, Table 'test.words' doesn't exist, when using table: w
drop table t1; drop table t1;
drop table t2; drop table t2;
drop table words2; drop table words2;
create database first;
use first;
set time_zone = 'UTC';
create event ee1 on schedule at '2035-12-31 20:01:23' do set @a=5;
show events;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
first ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
show create event ee1;
Event sql_mode Create Event
ee1 CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
drop database first;
create database second;
use second;
show events;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
second ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
show create event ee1;
Event sql_mode Create Event
ee1 NO_AUTO_VALUE_ON_ZERO CREATE EVENT `ee1` ON SCHEDULE AT '2035-12-31 20:01:23' ON COMPLETION NOT PRESERVE ENABLE DO set @a=5
create event ee2 on schedule at '2018-12-31 21:01:23' do set @a=5;
create event ee3 on schedule at '2030-12-31 22:01:23' do set @a=5;
show events;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
second ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
second ee2 root@localhost ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
second ee3 root@localhost ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
drop database second;
create database third;
use third;
show events;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
third ee1 root@localhost ONE TIME 2035-12-31 20:01:23 NULL NULL NULL NULL ENABLED
third ee2 root@localhost ONE TIME 2018-12-31 21:01:23 NULL NULL NULL NULL ENABLED
third ee3 root@localhost ONE TIME 2030-12-31 22:01:23 NULL NULL NULL NULL ENABLED
drop database third;
set time_zone = 'SYSTEM';
use test;
...@@ -1166,3 +1166,43 @@ drop table t1; ...@@ -1166,3 +1166,43 @@ drop table t1;
drop table t2; drop table t2;
drop table words2; drop table words2;
#
# BUG# 16853: mysqldump doesn't show events
#
create database first;
use first;
set time_zone = 'UTC';
## prove one works
create event ee1 on schedule at '2035-12-31 20:01:23' do set @a=5;
show events;
show create event ee1;
--exec $MYSQL_DUMP --events first > $MYSQLTEST_VARDIR/tmp/bug16853-1.sql
drop database first;
create database second;
use second;
--exec $MYSQL second < $MYSQLTEST_VARDIR/tmp/bug16853-1.sql
show events;
show create event ee1;
## prove three works
# start with one from the previous restore
create event ee2 on schedule at '2018-12-31 21:01:23' do set @a=5;
create event ee3 on schedule at '2030-12-31 22:01:23' do set @a=5;
show events;
--exec $MYSQL_DUMP --events second > $MYSQLTEST_VARDIR/tmp/bug16853-2.sql
drop database second;
create database third;
use third;
--exec $MYSQL third < $MYSQLTEST_VARDIR/tmp/bug16853-2.sql
show events;
drop database third;
# revert back to normal settings
set time_zone = 'SYSTEM';
use test;
#####
...@@ -1063,8 +1063,6 @@ Event_timed::get_create_event(THD *thd, String *buf) ...@@ -1063,8 +1063,6 @@ Event_timed::get_create_event(THD *thd, String *buf)
DBUG_RETURN(EVEX_MICROSECOND_UNSUP); DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
buf->append(STRING_WITH_LEN("CREATE EVENT ")); buf->append(STRING_WITH_LEN("CREATE EVENT "));
append_identifier(thd, buf, dbname.str, dbname.length);
buf->append(STRING_WITH_LEN("."));
append_identifier(thd, buf, name.str, name.length); append_identifier(thd, buf, name.str, name.length);
buf->append(STRING_WITH_LEN(" ON SCHEDULE ")); buf->append(STRING_WITH_LEN(" ON SCHEDULE "));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment