From 8d4f74be2d9b00e435fb22475414a0a68729092f Mon Sep 17 00:00:00 2001
From: unknown <andrey@lmy004.>
Date: Tue, 14 Feb 2006 16:20:48 +0100
Subject: [PATCH] - final fixes for bug#16431 (Events: An event which alters
 itself disappears) - fix for bug#16423 (Events: SHOW CREATE EVENT doesn't
 work) - this Changeset commits makes CREATE/UPDATE/DELETE EVENT real DDL
 statements   by committing the currently open transaction before they are
 executed. - this Changeset also fixes a trailing space problem since the very
 early days   of the internal cron - adds sophisticated checking of whether
 mysql.event was tampered accidentally   or with purpose by an user. - adds a
 lot of inline function documentation - documents everything left  
 uncodumented - INTERVAL_XXXX to XXX in I_S.EVENTS.INTERVAL_FIELD

WL#1034 (Internal CRON)


mysql-test/r/events.result:
  update result
mysql-test/t/events.test:
  add test cases for SHOW CREATE EVENT
  add test cases where the structure of mysql.event is changed and error reporting in this case
sql/event.cc:
  - do a lot more checking on mysql.event whether it's valid
    introduced generic function table_check_intact() which can be used also
    for checking whether a system table (mysql.*) has been tampered by user
    and report an error in this case. The checking is quite strict, thus
    maybe some mechanism can be added later that loosens this like some
    session variable, for instance, i_am_aware_that_i_can_damage_my_data
    so the table will be opened nevertheless we think that it's not valid.
  - add evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
  - document a loooot. not a single function left undocumented.
sql/event.h:
  - add evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
  - change get_show_create_event() to get_create_event()
  - add TABLE_FIELD_W_TYPE used by table_check_intact()
  - add event_timed::sql_mode so it can be used by show create event. currently
    always 0, will be fixed by a patch for another bug. At least makes the code
    of show create event complete.
sql/event_executor.cc:
  - add evex_check_system_tables() that checks on boot and event
    main thread startup that mysql.db and mysql.user tables are correct.
  - document everything!
sql/event_priv.h:
  remove a line
sql/event_timed.cc:
  - implement SHOW CREATE EVENT
  - document undocumented functions!
sql/share/errmsg.txt:
  - fix an error message and add two new
sql/sql_acl.cc:
  - add mysql.db table definition to use by table_check_intact()
  - exchange some of the positions by numbers from mysql.db to enum names (see sql_acl.h)
sql/sql_acl.h:
  - define the structure of mysql.db table
sql/sql_parse.cc:
  - handle SQLCOM_SHOW_CREATE_EVENT
  - end the current transaction becase CREATE/UPDATE/DELETE EVENT is a DDL
    statement
sql/sql_show.cc:
  - remove interval_type_to_name
  - use common function event_reconstruct_interval_expression()
    that reconstructs the expression given at create/alter, to some
    extent - interval of 2:62 MINUTE_SECOND will be reconstructed as
    interval of 3:02 MINUTE_SECOND!
sql/sql_yacc.yy:
  init the definer of event_timed also when doing SHOW CREATE EVENT
  because it's needed for checking into mysql.event
sql/table.cc:
  - remove stale code. only mysql.event should be a 'system_table'
  - add table_check_intact() to check the consistency of a table.
    mostly usable with mysql.xxx tables.
sql/table.h:
  - export TABLE_FIELD_W_TYPE and table_check_intact() which are used for
    checking the structure of a table. mostly usable for mysql.xxx tables.
---
 mysql-test/r/events.result | 207 ++++++++++++++--
 mysql-test/t/events.test   | 132 ++++++++++
 sql/event.cc               | 486 +++++++++++++++++++++++++++++++++++--
 sql/event.h                |  18 +-
 sql/event_executor.cc      | 189 ++++++++++++++-
 sql/event_priv.h           |   1 -
 sql/event_timed.cc         | 159 +++++++++---
 sql/share/errmsg.txt       |   8 +-
 sql/sql_acl.cc             | 122 +++++++++-
 sql/sql_acl.h              |  30 +++
 sql/sql_parse.cc           |  11 +-
 sql/sql_show.cc            |  31 +--
 sql/sql_yacc.yy            |   4 +
 sql/table.cc               | 142 ++++++++++-
 sql/table.h                |  11 +
 15 files changed, 1421 insertions(+), 130 deletions(-)

diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result
index 41f944ab08..b9acdb540e 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -24,7 +24,7 @@ sleep(3)
 0
 select db, name, body, status, interval_field, interval_value from mysql.event;
 db	name	body	status	interval_field	interval_value
-events_test	e_43	 set @a = 4	ENABLED	SECOND	1
+events_test	e_43	set @a = 4	ENABLED	SECOND	1
 drop event e_43;
 select sleep(1);
 sleep(1)
@@ -41,13 +41,178 @@ count(*)
 0
 drop event event3;
 drop table t_event3;
+set names utf8;
+CREATE EVENT root6 ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1;
+SHOW CREATE EVENT root6;
+Event	sql_mode	Create Event
+root6		CREATE EVENT `events_test`.`root6` ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1
+create event root7 on schedule every 2 year do select 1;
+SHOW CREATE EVENT root7;
+Event	sql_mode	Create Event
+root7		CREATE EVENT `events_test`.`root7` ON SCHEDULE EVERY 2 YEAR ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root8 on schedule every '2:5' year_month do select 1;
+SHOW CREATE EVENT root8;
+Event	sql_mode	Create Event
+root8		CREATE EVENT `events_test`.`root8` ON SCHEDULE EVERY '2-5' YEAR_MONTH ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root8_1 on schedule every '2:15' year_month do select 1;
+SHOW CREATE EVENT root8_1;
+Event	sql_mode	Create Event
+root8_1		CREATE EVENT `events_test`.`root8_1` ON SCHEDULE EVERY '3-3' YEAR_MONTH ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root9 on schedule every 2 week ON COMPLETION PRESERVE DISABLE COMMENT '泻芯屑械薪褌邪褉 薪邪 泻懈褉懈谢懈褑邪' do select 1;
+SHOW CREATE EVENT root9;
+Event	sql_mode	Create Event
+root9		CREATE EVENT `events_test`.`root9` ON SCHEDULE EVERY 2 WEEK ON COMPLETION PRESERVE DISABLE COMMENT '泻芯屑械薪褌邪褉 薪邪 泻懈褉懈谢懈褑邪' DO select 1
+create event root10 on schedule every '20:5' day_hour do select 1;
+SHOW CREATE EVENT root10;
+Event	sql_mode	Create Event
+root10		CREATE EVENT `events_test`.`root10` ON SCHEDULE EVERY '20 5' DAY_HOUR ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root11 on schedule every '20:25' day_hour do select 1;
+SHOW CREATE EVENT root11;
+Event	sql_mode	Create Event
+root11		CREATE EVENT `events_test`.`root11` ON SCHEDULE EVERY '21 1' DAY_HOUR ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root12 on schedule every '20:25' hour_minute do select 1;
+SHOW CREATE EVENT root12;
+Event	sql_mode	Create Event
+root12		CREATE EVENT `events_test`.`root12` ON SCHEDULE EVERY '20:25' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root13 on schedule every '25:25' hour_minute do select 1;
+SHOW CREATE EVENT root13;
+Event	sql_mode	Create Event
+root13		CREATE EVENT `events_test`.`root13` ON SCHEDULE EVERY '25:25' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root13_1 on schedule every '11:65' hour_minute do select 1;
+SHOW CREATE EVENT root13_1;
+Event	sql_mode	Create Event
+root13_1		CREATE EVENT `events_test`.`root13_1` ON SCHEDULE EVERY '12:5' HOUR_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root14 on schedule every '35:35' minute_second do select 1;
+SHOW CREATE EVENT root14;
+Event	sql_mode	Create Event
+root14		CREATE EVENT `events_test`.`root14` ON SCHEDULE EVERY '35:35' MINUTE_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root15 on schedule every '35:66' minute_second do select 1;
+SHOW CREATE EVENT root15;
+Event	sql_mode	Create Event
+root15		CREATE EVENT `events_test`.`root15` ON SCHEDULE EVERY '36:6' MINUTE_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root16 on schedule every '35:56' day_minute do select 1;
+SHOW CREATE EVENT root16;
+Event	sql_mode	Create Event
+root16		CREATE EVENT `events_test`.`root16` ON SCHEDULE EVERY '1 11:56' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root17 on schedule every '35:12:45' day_minute do select 1;
+SHOW CREATE EVENT root17;
+Event	sql_mode	Create Event
+root17		CREATE EVENT `events_test`.`root17` ON SCHEDULE EVERY '35 12:45' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root17_1 on schedule every '35:25:65' day_minute do select 1;
+SHOW CREATE EVENT root17_1;
+Event	sql_mode	Create Event
+root17_1		CREATE EVENT `events_test`.`root17_1` ON SCHEDULE EVERY '36 2:5' DAY_MINUTE ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root18 on schedule every '35:12:45' hour_second do select 1;
+SHOW CREATE EVENT root18;
+Event	sql_mode	Create Event
+root18		CREATE EVENT `events_test`.`root18` ON SCHEDULE EVERY '35:12:45' HOUR_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root19 on schedule every '15:59:85' hour_second do select 1;
+SHOW CREATE EVENT root19;
+Event	sql_mode	Create Event
+root19		CREATE EVENT `events_test`.`root19` ON SCHEDULE EVERY '16:0:25' HOUR_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
+create event root20 on schedule every '50:20:12:45' day_second do select 1;
+SHOW CREATE EVENT root20;
+Event	sql_mode	Create Event
+root20		CREATE EVENT `events_test`.`root20` ON SCHEDULE EVERY '50 20:12:45' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE DO select 1
+set names cp1251;
+create event 痼篁21 on schedule every '50:23:59:95' day_second COMMENT '蝾忄 � 1251 觐戾眚囵' do select 1;
+SHOW CREATE EVENT 痼篁21;
+Event	sql_mode	Create Event
+痼篁21		CREATE EVENT `events_test`.`痼篁21` ON SCHEDULE EVERY '51 0:0:35' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE COMMENT '蝾忄 � 1251 觐戾眚囵' DO select 1
+insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
+show create event root22;
+ERROR HY000: Microseconds intervals are not yet supported
+SHOW EVENTS;
+ERROR HY000: Microseconds intervals are not yet supported
+drop event root22;
+drop event root6;
+drop event root7;
+drop event root8;
+drop event root8_1;
+drop event root9;
+drop event root10;
+drop event root11;
+drop event root12;
+drop event root13;
+drop event root13_1;
+drop event root14;
+drop event root15;
+drop event root16;
+drop event root17;
+drop event root17_1;
+drop event root18;
+drop event root19;
+drop event root20;
+drop event 痼篁21;
+set names latin1;
+CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
+SHOW EVENTS;
+Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+events_test	intact_check	root@localhost	RECURRING	NULL	10	10 HOUR	#	#	ENABLED
+ALTER TABLE mysql.event ADD dummy INT FIRST;
+SHOW EVENTS;
+ERROR HY000: Column count of mysql.event is wrong. Table probably corrupted. Expected 15, found 16.
+ALTER TABLE mysql.event DROP dummy, ADD dummy2 VARCHAR(64) FIRST;
+SHOW EVENTS;
+ERROR HY000: Column count of mysql.event is wrong. Table probably corrupted. Expected 15, found 16.
+ALTER TABLE mysql.event DROP dummy2;
+SHOW EVENTS;
+Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+events_test	intact_check	root@localhost	RECURRING	NULL	10	10 HOUR	#	#	ENABLED
+CREATE TABLE event_like LIKE mysql.event;
+INSERT INTO event_like SELECT * FROM mysql.event;
+ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
+SHOW CREATE TABLE mysql.event;
+Table	Create Table
+event	CREATE TABLE `event` (
+  `db` char(20) character set utf8 collate utf8_bin NOT NULL default '',
+  `name` char(64) character set utf8 collate utf8_bin NOT NULL default '',
+  `body` longblob NOT NULL,
+  `definer` char(77) character set utf8 collate utf8_bin NOT NULL default '',
+  `execute_at` datetime default NULL,
+  `interval_value` int(11) default NULL,
+  `interval_field` enum('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL,
+  `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
+  `modified` timestamp NOT NULL default '0000-00-00 00:00:00',
+  `last_executed` datetime default NULL,
+  `starts` datetime default NULL,
+  `ends` datetime default NULL,
+  `status` enum('ENABLED','DISABLED') NOT NULL default 'ENABLED',
+  `on_completion` enum('DROP','PRESERVE') NOT NULL default 'DROP',
+  `comment` char(64) character set utf8 collate utf8_bin NOT NULL default '',
+  PRIMARY KEY  (`definer`,`db`,`name`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ALTER TABLE mysql.event MODIFY db char(64) character set utf8 collate utf8_bin default '';
+"This should work"
+SHOW EVENTS;
+Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+events_test	intact_check	root@localhost	RECURRING	NULL	10	10 HOUR	#	#	ENABLED
+ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ALTER TABLE mysql.event DROP comment, DROP starts;
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+ERROR HY000: Column count of mysql.event is wrong. Table probably corrupted. Expected 15, found 13.
+DROP TABLE mysql.event;
+CREATE TABLE mysql.event like event_like;
+INSERT INTO  mysql.event SELECT * FROM event_like;
+DROP TABLE event_like;
+SHOW EVENTS;
+Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+events_test	intact_check	root@localhost	RECURRING	NULL	10	10 HOUR	#	#	ENABLED
+DROP EVENT intact_check;
 create event one_event on schedule every 10 second do select 123;
 SHOW EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	one_event	root@localhost	RECURRING	NULL	10	INTERVAL_SECOND	#	#	ENABLED
+events_test	one_event	root@localhost	RECURRING	NULL	10	10 SECOND	#	#	ENABLED
 SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
 EVENT_CATALOG	EVENT_SCHEMA	EVENT_NAME	DEFINER	EVENT_BODY	EVENT_TYPE	EXECUTE_AT	INTERVAL_VALUE	INTERVAL_FIELD	STATUS	ON_COMPLETION	EVENT_COMMENT
-NULL	events_test	one_event	root@localhost	 select 123	RECURRING	NULL	10	INTERVAL_SECOND	ENABLED	NOT PRESERVE	
+NULL	events_test	one_event	root@localhost	select 123	RECURRING	NULL	10	10 SECOND	ENABLED	NOT PRESERVE	
 CREATE DATABASE events_test2;
 CREATE USER ev_test@localhost;
 GRANT ALL ON events_test.* to ev_test@localhost;
@@ -81,20 +246,20 @@ create event three_event on schedule every 20 second on completion preserve comm
 "Now we should see 3 events:";
 SHOW EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	one_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	three_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	two_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
+events_test	one_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	three_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	two_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
 "This should show us only 3 events:";
 SHOW FULL EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	one_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	three_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	two_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
+events_test	one_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	three_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	two_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
 "This should show us only 2 events:";
 SHOW FULL EVENTS LIKE 't%event';
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	three_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	two_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
+events_test	three_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	two_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
 "This should show us no events:";
 SHOW FULL EVENTS FROM test LIKE '%';
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
@@ -102,20 +267,20 @@ DROP DATABASE events_test2;
 "should see 1 event:";
 SHOW EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	one_event	root@localhost	RECURRING	NULL	10	INTERVAL_SECOND	#	#	ENABLED
+events_test	one_event	root@localhost	RECURRING	NULL	10	10 SECOND	#	#	ENABLED
 "we should see 4 events now:";
 SHOW FULL EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	one_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	three_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	two_event	ev_test@localhost	RECURRING	NULL	20	INTERVAL_SECOND	#	#	ENABLED
-events_test	one_event	root@localhost	RECURRING	NULL	10	INTERVAL_SECOND	#	#	ENABLED
+events_test	one_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	three_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	two_event	ev_test@localhost	RECURRING	NULL	20	20 SECOND	#	#	ENABLED
+events_test	one_event	root@localhost	RECURRING	NULL	10	10 SECOND	#	#	ENABLED
 SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
 EVENT_CATALOG	EVENT_SCHEMA	EVENT_NAME	DEFINER	EVENT_BODY	EVENT_TYPE	EXECUTE_AT	INTERVAL_VALUE	INTERVAL_FIELD	STATUS	ON_COMPLETION	EVENT_COMMENT
-NULL	events_test	one_event	ev_test@localhost	 select 123	RECURRING	NULL	20	INTERVAL_SECOND	ENABLED	NOT PRESERVE	
-NULL	events_test	three_event	ev_test@localhost	 select 123	RECURRING	NULL	20	INTERVAL_SECOND	ENABLED	PRESERVE	three event
-NULL	events_test	two_event	ev_test@localhost	 select 123	RECURRING	NULL	20	INTERVAL_SECOND	ENABLED	NOT PRESERVE	two event
-NULL	events_test	one_event	root@localhost	 select 123	RECURRING	NULL	10	INTERVAL_SECOND	ENABLED	NOT PRESERVE	
+NULL	events_test	one_event	ev_test@localhost	select 123	RECURRING	NULL	20	20 SECOND	ENABLED	NOT PRESERVE	
+NULL	events_test	three_event	ev_test@localhost	select 123	RECURRING	NULL	20	20 SECOND	ENABLED	PRESERVE	three event
+NULL	events_test	two_event	ev_test@localhost	select 123	RECURRING	NULL	20	20 SECOND	ENABLED	NOT PRESERVE	two event
+NULL	events_test	one_event	root@localhost	select 123	RECURRING	NULL	10	10 SECOND	ENABLED	NOT PRESERVE	
 drop event one_event;
 drop event two_event;
 drop event three_event;
@@ -124,7 +289,7 @@ drop event one_event;
 create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
 select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
 db	name	body	definer	convert_tz(execute_at, 'UTC', 'SYSTEM')	on_completion
-events_test	e_26	 set @a = 5	root@localhost	2017-01-01 00:00:00	DROP
+events_test	e_26	set @a = 5	root@localhost	2017-01-01 00:00:00	DROP
 drop event e_26;
 create event e_26 on schedule at NULL disabled do set @a = 5;
 ERROR HY000: Incorrect AT value: 'NULL'
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index be24d49039..741ff904d1 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -33,6 +33,138 @@ select count(*) from t_event3;
 drop event event3;
 drop table t_event3;
 
+
+set names utf8;
+#
+# SHOW CREATE EVENT test begin
+#
+CREATE EVENT root6 ON SCHEDULE EVERY '10:20' MINUTE_SECOND ON COMPLETION PRESERVE ENABLE COMMENT 'some comment' DO select 1;
+SHOW CREATE EVENT root6;
+create event root7 on schedule every 2 year do select 1;
+SHOW CREATE EVENT root7;
+create event root8 on schedule every '2:5' year_month do select 1;
+SHOW CREATE EVENT root8;
+create event root8_1 on schedule every '2:15' year_month do select 1;
+SHOW CREATE EVENT root8_1;
+create event root9 on schedule every 2 week ON COMPLETION PRESERVE DISABLE COMMENT '泻芯屑械薪褌邪褉 薪邪 泻懈褉懈谢懈褑邪' do select 1;
+SHOW CREATE EVENT root9;
+create event root10 on schedule every '20:5' day_hour do select 1;
+SHOW CREATE EVENT root10;
+create event root11 on schedule every '20:25' day_hour do select 1;
+SHOW CREATE EVENT root11;
+create event root12 on schedule every '20:25' hour_minute do select 1;
+SHOW CREATE EVENT root12;
+create event root13 on schedule every '25:25' hour_minute do select 1;
+SHOW CREATE EVENT root13;
+create event root13_1 on schedule every '11:65' hour_minute do select 1;
+SHOW CREATE EVENT root13_1;
+create event root14 on schedule every '35:35' minute_second do select 1;
+SHOW CREATE EVENT root14;
+create event root15 on schedule every '35:66' minute_second do select 1;
+SHOW CREATE EVENT root15;
+create event root16 on schedule every '35:56' day_minute do select 1;
+SHOW CREATE EVENT root16;
+create event root17 on schedule every '35:12:45' day_minute do select 1;
+SHOW CREATE EVENT root17;
+create event root17_1 on schedule every '35:25:65' day_minute do select 1;
+SHOW CREATE EVENT root17_1;
+create event root18 on schedule every '35:12:45' hour_second do select 1;
+SHOW CREATE EVENT root18;
+create event root19 on schedule every '15:59:85' hour_second do select 1;
+SHOW CREATE EVENT root19;
+create event root20 on schedule every '50:20:12:45' day_second do select 1;
+SHOW CREATE EVENT root20;
+set names cp1251;
+create event 痼篁21 on schedule every '50:23:59:95' day_second COMMENT '蝾忄 � 1251 觐戾眚囵' do select 1;
+SHOW CREATE EVENT 痼篁21;
+insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
+--error 1535
+show create event root22;
+--error 1535
+SHOW EVENTS;
+drop event root22;
+drop event root6;
+drop event root7;
+drop event root8;
+drop event root8_1;
+drop event root9;
+drop event root10;
+drop event root11;
+drop event root12;
+drop event root13;
+drop event root13_1;
+drop event root14;
+drop event root15;
+drop event root16;
+drop event root17;
+drop event root17_1;
+drop event root18;
+drop event root19;
+drop event root20;
+drop event 痼篁21;
+
+set names latin1;
+#
+# SHOW CREATE EVENT test end
+#
+
+#
+# mysql.event intact checking start
+#
+# There should be at least 1 second between the ALTERs or we can't catch the change of create_time!!
+#
+CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
+--replace_column 8 # 9 #
+SHOW EVENTS;
+ALTER TABLE mysql.event ADD dummy INT FIRST;
+--error 1525
+SHOW EVENTS;
+ALTER TABLE mysql.event DROP dummy, ADD dummy2 VARCHAR(64) FIRST;
+--error 1525
+SHOW EVENTS;
+ALTER TABLE mysql.event DROP dummy2;
+--replace_column 8 # 9 #
+SHOW EVENTS;
+CREATE TABLE event_like LIKE mysql.event;
+INSERT INTO event_like SELECT * FROM mysql.event;
+#sleep a bit or we won't catch the change of time
+--sleep 1
+ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
+#wait a bit or we won't see the difference because of seconds resolution
+--sleep 1
+SHOW CREATE TABLE mysql.event;
+--error 1526
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+--sleep 1
+ALTER TABLE mysql.event MODIFY db char(64) character set utf8 collate utf8_bin default '';
+--sleep 1
+--echo "This should work"
+--replace_column 8 # 9 #
+SHOW EVENTS;
+--sleep 1
+ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
+--error 1526
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+--sleep 1
+ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
+--error 1526
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+--sleep 1
+ALTER TABLE mysql.event DROP comment, DROP starts;
+--sleep 1
+--error 1525
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+DROP TABLE mysql.event;
+CREATE TABLE mysql.event like event_like;
+INSERT INTO  mysql.event SELECT * FROM event_like;
+DROP TABLE event_like;
+--replace_column 8 # 9 #
+SHOW EVENTS;
+DROP EVENT intact_check;
+#
+# mysql.event intact checking end
+#
+
 #
 #INFORMATION_SCHEMA.EVENTS test begin
 #
diff --git a/sql/event.cc b/sql/event.cc
index abca622835..a5cf76240b 100644
--- a/sql/event.cc
+++ b/sql/event.cc
@@ -51,8 +51,6 @@
  
  - Make event_timed::get_show_create_event() work
 
- - Add function documentation whenever needed.
-
  - Add logging to file
 
  - Move comparison code to class event_timed
@@ -66,8 +64,144 @@ Warning:
 
 QUEUE EVEX_EQ_NAME;
 MEM_ROOT evex_mem_root;
+time_t mysql_event_last_create_time= 0L;
+
+
+static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
+  {
+    {(char *) STRING_WITH_LEN("db")},            
+    {(char *) STRING_WITH_LEN("char(64)")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("name")},
+    {(char *) STRING_WITH_LEN("char(64)")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("body")},
+    {(char *) STRING_WITH_LEN("longblob")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("definer")},
+    {(char *) STRING_WITH_LEN("char(77)")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("execute_at")},
+    {(char *) STRING_WITH_LEN("datetime")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("interval_value")},
+    {(char *) STRING_WITH_LEN("int(11)")},
+    {NULL, 0}
+  },
+  {
+    {(char *) STRING_WITH_LEN("interval_field")},
+    {(char *) STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
+    "'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
+    "'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
+    "'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
+    "'SECOND_MICROSECOND')")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("created")},
+    {(char *) STRING_WITH_LEN("timestamp")},
+    {NULL, 0}
+  },
+  {
+    {(char *) STRING_WITH_LEN("modified")},
+    {(char *) STRING_WITH_LEN("timestamp")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("last_executed")},
+    {(char *) STRING_WITH_LEN("datetime")},
+  },
+  {
+    {(char *) STRING_WITH_LEN("starts")},
+    {(char *) STRING_WITH_LEN("datetime")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("ends")},
+    {(char *) STRING_WITH_LEN("datetime")},
+    {NULL, 0}
+  },
+  {
+    {(char *) STRING_WITH_LEN("status")},
+    {(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("on_completion")},
+    {(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")},
+    {NULL, 0}
+  },
+/*
+  {
+    {(char *) STRING_WITH_LEN("sql_mode")},
+    {(char *) STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
+    "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
+    "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
+    "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
+    "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
+    "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
+    "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
+    "'HIGH_NOT_PRECEDENCE')")},
+    {NULL, 0}
+  },
+*/
+  {
+    {(char *) STRING_WITH_LEN("comment")},
+    {(char *) STRING_WITH_LEN("char(64)")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  }
+};
+
+
+LEX_STRING interval_type_to_name[] = {
+  {(char *) STRING_WITH_LEN("YEAR")}, 
+  {(char *) STRING_WITH_LEN("QUARTER")}, 
+  {(char *) STRING_WITH_LEN("MONTH")}, 
+  {(char *) STRING_WITH_LEN("DAY")}, 
+  {(char *) STRING_WITH_LEN("HOUR")}, 
+  {(char *) STRING_WITH_LEN("MINUTE")}, 
+  {(char *) STRING_WITH_LEN("WEEK")}, 
+  {(char *) STRING_WITH_LEN("SECOND")}, 
+  {(char *) STRING_WITH_LEN("MICROSECOND")}, 
+  {(char *) STRING_WITH_LEN("YEAR_MONTH")}, 
+  {(char *) STRING_WITH_LEN("DAY_HOUR")}, 
+  {(char *) STRING_WITH_LEN("DAY_MINUTE")}, 
+  {(char *) STRING_WITH_LEN("DAY_SECOND")}, 
+  {(char *) STRING_WITH_LEN("HOUR_MINUTE")}, 
+  {(char *) STRING_WITH_LEN("HOUR_SECOND")}, 
+  {(char *) STRING_WITH_LEN("MINUTE_SECOND")}, 
+  {(char *) STRING_WITH_LEN("DAY_MICROSECOND")}, 
+  {(char *) STRING_WITH_LEN("HOUR_MICROSECOND")}, 
+  {(char *) STRING_WITH_LEN("MINUTE_MICROSECOND")}, 
+  {(char *) STRING_WITH_LEN("SECOND_MICROSECOND")}
+}; 
 
 
+
+/*
+  Inits the scheduler queue - prioritized queue from mysys/queue.c
+  
+  Synopsis
+    evex_queue_init()
+    
+      queue - pointer the the memory to be initialized as queue. has to be
+              allocated from the caller
+
+  Notes
+    During initialization the queue is sized for 30 events, and when is full
+    will auto extent with 30.
+*/
+
 void
 evex_queue_init(EVEX_QUEUE_TYPE *queue)
 {
@@ -77,6 +211,24 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue)
 }
 
 
+/*
+  Compares 2 LEX strings regarding case.
+  
+  Synopsis
+    my_time_compare()
+    
+      s - first LEX_STRING
+      t - second LEX_STRING
+      cs - charset
+
+  RETURNS:
+   -1   - s < t
+    0   - s == t
+    1   - s > t
+    
+  Notes
+    TIME.second_part is not considered during comparison
+*/
 
 int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
 {
@@ -85,6 +237,24 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
 }
 
 
+/*
+  Compares 2 TIME structures
+  
+  Synopsis
+    my_time_compare()
+    
+      a - first TIME
+      b - second time
+  
+  RETURNS:
+   -1   - a < b
+    0   - a == b
+    1   - a > b
+    
+  Notes
+    TIME.second_part is not considered during comparison
+*/
+
 int
 my_time_compare(TIME *a, TIME *b)
 {
@@ -106,6 +276,24 @@ my_time_compare(TIME *a, TIME *b)
 }
 
 
+/*
+  Compares the execute_at members of 2 event_timed instances
+  
+  Synopsis
+    event_timed_compare()
+    
+      a - first event_timed object
+      b - second event_timed object
+  
+  RETURNS:
+   -1   - a->execute_at < b->execute_at
+    0   - a->execute_at == b->execute_at
+    1   - a->execute_at > b->execute_at
+    
+  Notes
+    execute_at.second_part is not considered during comparison
+*/
+
 int
 event_timed_compare(event_timed *a, event_timed *b)
 {
@@ -114,7 +302,24 @@ event_timed_compare(event_timed *a, event_timed *b)
 
 
 /*
-  Callback for the prio queue
+  Compares the execute_at members of 2 event_timed instances.
+  Used as callback for the prioritized queue when shifting
+  elements inside.
+  
+  Synopsis
+    event_timed_compare()
+  
+      vptr - not used (set it to NULL)
+      a    - first event_timed object
+      b    - second event_timed object
+  
+  RETURNS:
+   -1   - a->execute_at < b->execute_at
+    0   - a->execute_at == b->execute_at
+    1   - a->execute_at > b->execute_at
+    
+  Notes
+    execute_at.second_part is not considered during comparison
 */
 
 int 
@@ -124,6 +329,145 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
 }
 
 
+/*
+  Reconstructs interval expression from interval type and expression
+  value that is in form of a value of the smalles entity:
+  For
+    YEAR_MONTH - expression is in months
+    DAY_MINUTE - expression is in minutes
+    
+  Synopsis
+    event_reconstruct_interval_expression()
+      buf - preallocated String buffer to add the value to
+      interval - the interval type (for instance YEAR_MONTH)
+      expression - the value in the lowest entity
+  
+  RETURNS
+   0 - OK
+   1 - Error
+  
+ 
+*/
+
+int
+event_reconstruct_interval_expression(String *buf,
+                                      interval_type interval,
+                                      longlong expression)
+{
+  ulonglong expr= expression;
+  char tmp_buff[128], *end;
+  bool close_quote= TRUE;
+  int multipl= 0;
+  char separator=':';
+
+  switch (interval) {
+  case INTERVAL_YEAR_MONTH:
+    multipl= 12;
+    separator= '-';
+    goto common_1_lev_code;
+  case INTERVAL_DAY_HOUR:
+    multipl= 24;
+    separator= ' ';
+    goto common_1_lev_code;
+  case INTERVAL_HOUR_MINUTE:
+  case INTERVAL_MINUTE_SECOND:
+    multipl= 60;      
+common_1_lev_code:
+    buf->append('\'');
+    end= longlong10_to_str(expression/multipl, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));
+    expr= expr - (expr/multipl)*multipl;
+    break;
+  case INTERVAL_DAY_MINUTE:
+  {
+    int tmp_expr= expr;
+
+    tmp_expr/=(24*60);
+    buf->append('\'');
+    end= longlong10_to_str(tmp_expr, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// days
+    buf->append(' ');
+
+    tmp_expr= expr - tmp_expr*(24*60);//minutes left
+    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
+
+    expr= tmp_expr - (tmp_expr/60)*60;
+    /* the code after the switch will finish */
+  }
+    break;
+  case INTERVAL_HOUR_SECOND:
+  {
+    int tmp_expr= expr;
+
+    buf->append('\'');
+    end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
+    buf->append(':');
+
+    tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
+    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
+
+    expr= tmp_expr - (tmp_expr/60)*60;
+    /* the code after the switch will finish */
+  }
+    break;      
+  case INTERVAL_DAY_SECOND:
+  {
+    int tmp_expr= expr;
+
+    tmp_expr/=(24*3600);
+    buf->append('\'');
+    end= longlong10_to_str(tmp_expr, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// days
+    buf->append(' ');
+
+    tmp_expr= expr - tmp_expr*(24*3600);//seconds left
+    end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
+    buf->append(':');
+
+    tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
+    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
+    buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
+
+    expr= tmp_expr - (tmp_expr/60)*60;
+    /* the code after the switch will finish */
+  }
+    break;  
+  case INTERVAL_DAY_MICROSECOND:
+  case INTERVAL_HOUR_MICROSECOND:
+  case INTERVAL_MINUTE_MICROSECOND:
+  case INTERVAL_SECOND_MICROSECOND:
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0));
+    return 1;
+    break;
+  case INTERVAL_QUARTER:
+    expr/= 3;
+    close_quote= FALSE;
+    break;
+  case INTERVAL_WEEK:
+    expr/= 7;
+  default:
+    close_quote= FALSE;
+    break;
+  }
+  if (close_quote)
+    buf->append(separator);
+  end= longlong10_to_str(expr, tmp_buff, 10);
+  buf->append(tmp_buff, (uint) (end- tmp_buff));
+  if (close_quote)
+    buf->append('\'');
+    
+  buf->append(' ');
+  LEX_STRING *ival= &interval_type_to_name[interval];
+  buf->append(ival->str, ival->length);
+  
+  return 0;
+}
+
+
 /*
   Open mysql.event table for read
 
@@ -132,6 +476,7 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
       thd         Thread context
       lock_type   How to lock the table
       table       The table pointer
+
   RETURN
     1	Cannot lock table
     2   The table is corrupted - different number of fields
@@ -153,9 +498,10 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
   if (simple_open_n_lock_tables(thd, &tables))
     DBUG_RETURN(1);
   
-  if (tables.table->s->fields != EVEX_FIELD_COUNT)
+  if (table_check_intact(tables.table, EVEX_FIELD_COUNT, event_table_fields,
+                         &mysql_event_last_create_time,
+                         ER_EVENT_CANNOT_LOAD_FROM_TABLE))
   {
-    my_error(ER_EVENT_COL_COUNT_DOESNT_MATCH, MYF(0), "mysql", "event");
     close_thread_tables(thd);
     DBUG_RETURN(2);
   }
@@ -219,7 +565,6 @@ evex_db_find_event_aux(THD *thd, const LEX_STRING dbname,
 }
 
 
-
 /*
    Puts some data common to CREATE and ALTER EVENT into a row.
 
@@ -245,15 +590,9 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
 
   DBUG_ENTER("evex_fill_row");
 
-  if (table->s->fields != EVEX_FIELD_COUNT)
-  {
-    my_error(ER_EVENT_COL_COUNT_DOESNT_MATCH, MYF(0), "mysql", "event");
-    DBUG_RETURN(EVEX_GET_FIELD_FAILED);
-  }
-  
-  DBUG_PRINT("info", ("dbname.len=[%s]",et->dbname.str));  
-  DBUG_PRINT("info", ("name.len=[%s]",et->name.str));  
-  DBUG_PRINT("info", ("body=[%s]",et->body.str));  
+  DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));  
+  DBUG_PRINT("info", ("name  =[%s]", et->name.str));  
+  DBUG_PRINT("info", ("body  =[%s]", et->body.str));  
 
   if (table->field[field_num= EVEX_FIELD_DB]->
                   store(et->dbname.str, et->dbname.length, system_charset_info))
@@ -584,16 +923,19 @@ err:
 */
 
 static int
-db_find_event(THD *thd, sp_name *name, LEX_STRING definer, event_timed **ett,
-              TABLE *tbl)
+db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
+              TABLE *tbl, MEM_ROOT *root)
 {
   TABLE *table;
   int ret;
   char *ptr;
-  event_timed *et;  
+  event_timed *et=NULL;
   DBUG_ENTER("db_find_event");
   DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
 
+  if (!root)
+    root= &evex_mem_root;
+
   if (tbl)
     table= tbl;
   else if (evex_open_event_table(thd, TL_READ, &table))
@@ -603,7 +945,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING definer, event_timed **ett,
     goto done;
   }
 
-  if ((ret= evex_db_find_event_aux(thd, name->m_db, name->m_name, definer,
+  if ((ret= evex_db_find_event_aux(thd, name->m_db, name->m_name, *definer,
                                    table)))
   {
     my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
@@ -617,7 +959,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING definer, event_timed **ett,
 
     2)::load_from_row() is silent on error therefore we emit error msg here
   */
-  if ((ret= et->load_from_row(&evex_mem_root, table)))
+  if ((ret= et->load_from_row(root, table)))
   {
     my_error(ER_EVENT_CANNOT_LOAD_FROM_TABLE, MYF(0));
     goto done;
@@ -671,10 +1013,11 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
 
   thd->reset_n_backup_open_tables_state(&backup);
   // no need to use my_error() here because db_find_event() has done it
-  if ((ret= db_find_event(thd, spn, definer, &ett, NULL)))
+  ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
+  thd->restore_backup_open_tables_state(&backup);
+  if (ret)
     goto done;
 
-  thd->restore_backup_open_tables_state(&backup);
   /*
     allocate on evex_mem_root. if you call without evex_mem_root
     then sphead will not be cleared!
@@ -704,10 +1047,31 @@ done:
 }
 
 
+/*
+  Removes from queue in memory the event which is identified by the tupple
+  (db, name).
+
+   SYNOPSIS
+     evex_remove_from_cache()
+  
+       db       - db name
+       name     - event name
+       use_lock - whether to lock the mutex LOCK_event_arrays or not in case it
+                  has been already locked outside
+       is_drop  - if an event is currently being executed then we can also delete
+                  the event_timed instance, so we alarm the event that it should
+                  drop itself if this parameter is set to TRUE. It's false on
+                  ALTER EVENT.
+
+   RETURNS
+     0 - OK (always)
+*/
+
 static int
 evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
                        bool is_drop)
 {
+  //ToDo : Add definer to the tuple (db, name) to become triple
   uint i;
 
   DBUG_ENTER("evex_remove_from_cache");
@@ -755,8 +1119,6 @@ done:
 }
 
 
-
-
 /*
    The function exported to the world for creating of events.
 
@@ -814,8 +1176,8 @@ done:
           
    NOTES
      et contains data about dbname and event name. 
-     name is the new name of the event, if not null this means
-     that RENAME TO was specified in the query.
+     new_name is the new name of the event, if not null (this means
+     that RENAME TO was specified in the query)
 */
 
 int
@@ -923,3 +1285,75 @@ done:
   DBUG_RETURN(ret);
 }
 
+
+/*
+   SHOW CREATE EVENT
+
+   SYNOPSIS
+     evex_show_create_event()
+       thd        THD
+       spn        the name of the event (db, name)
+       definer    the definer of the event
+   
+   RETURNS
+     0  -  OK
+     1  - Error during writing to the wire
+          
+*/
+
+int
+evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
+{
+  int ret;
+  event_timed *et= NULL;
+  Open_tables_state backup;
+
+  DBUG_ENTER("evex_update_event");
+  DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
+
+  thd->reset_n_backup_open_tables_state(&backup);
+  ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root);
+  thd->restore_backup_open_tables_state(&backup);
+
+  if (!ret && et)
+  {    
+    Protocol *protocol= thd->protocol;
+    char show_str_buf[768];
+    String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
+    List<Item> field_list;
+    const char *sql_mode_str;
+    ulong sql_mode_len=0;
+    
+    show_str.length(0);
+    show_str.set_charset(system_charset_info);
+
+    if (et->get_create_event(thd, &show_str))
+      DBUG_RETURN(1);
+
+    field_list.push_back(new Item_empty_string("Event", NAME_LEN));
+
+    sql_mode_str=
+      sys_var_thd_sql_mode::symbolic_mode_representation(thd, et->sql_mode,
+                                                         &sql_mode_len);
+
+    field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+
+    field_list.push_back(new Item_empty_string("Create Event",
+                                               show_str.length()));
+    if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+                                           Protocol::SEND_EOF))
+      DBUG_RETURN(1);
+
+    protocol->prepare_for_resend();
+    protocol->store(et->name.str, et->name.length, system_charset_info);
+
+    protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+
+    
+    protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
+    ret= protocol->write();
+    send_eof(thd);
+  }
+  
+  DBUG_RETURN(ret);
+}
diff --git a/sql/event.h b/sql/event.h
index 3d00ca388b..ed75b68b30 100644
--- a/sql/event.h
+++ b/sql/event.h
@@ -108,6 +108,7 @@ public:
   enum enum_event_on_completion on_completion;
   enum enum_event_status status;
   sp_head *sphead;
+  ulong sql_mode;
 
   const uchar *body_begin;
   
@@ -118,8 +119,9 @@ public:
   event_timed():running(0), status_changed(false), last_executed_changed(false),
                 expression(0), created(0), modified(0),
                 on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
-                status(MYSQL_EVENT_ENABLED), sphead(0), dropped(false),
-                free_sphead_on_delete(true), flags(0)
+                status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
+                body_begin(0), dropped(false), free_sphead_on_delete(true),
+                flags(0)
                 
   {
     pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
@@ -176,8 +178,8 @@ public:
   bool
   update_fields(THD *thd);
 
-  char *
-  get_show_create_event(THD *thd, uint32 *length);
+  int
+  get_create_event(THD *thd, String *buf);
   
   int
   execute(THD *thd, MEM_ROOT *mem_root= NULL);
@@ -220,8 +222,16 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
 int
 evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
 
+int
+evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer);
+
 int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
 
+int
+event_reconstruct_interval_expression(String *buf,
+                                      interval_type interval,
+                                      longlong expression);
+
 int
 init_events();
 
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index 7960f1e175..9c247f11da 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -32,9 +32,9 @@
 extern  ulong thread_created;
 extern const char *my_localhost;
 
-pthread_mutex_t LOCK_event_arrays,
-                LOCK_workers_count,
-                LOCK_evex_running;
+pthread_mutex_t LOCK_event_arrays,  // mutex for when working with the queue
+                LOCK_workers_count, // mutex for when inc/dec uint workers_count
+                LOCK_evex_running;  // mutes for managing bool evex_is_running
 
 
 bool evex_is_running= false;
@@ -61,6 +61,19 @@ event_executor_worker(void *arg);
 pthread_handler_t
 event_executor_main(void *arg);
 
+
+/*
+   Returns the seconds difference of 2 TIME structs
+
+   SYNOPSIS
+     evex_time_diff()
+      a - TIME struct 1
+      b - TIME struct 2
+   
+   Returns:
+    the seconds difference
+*/
+
 static int
 evex_time_diff(TIME *a, TIME *b)
 {
@@ -68,6 +81,19 @@ evex_time_diff(TIME *a, TIME *b)
 }
 
 
+/*
+   Inits the mutexes used by the scheduler module
+
+   SYNOPSIS
+     evex_init_mutexes()
+          
+   NOTES
+    The mutexes are :
+      LOCK_event_arrays
+      LOCK_workers_count
+      LOCK_evex_running
+*/
+
 static void
 evex_init_mutexes()
 {
@@ -83,6 +109,75 @@ evex_init_mutexes()
 }
 
 
+/*
+  Opens mysql.db and mysql.user and checks whether
+  1. mysql.db has column Event_priv at column 20 (0 based);
+  2. mysql.user has column Event_priv at column 29 (0 based);
+  
+  Synopsis
+    evex_check_system_tables()
+*/
+
+void
+evex_check_system_tables()
+{
+  THD *thd= current_thd;
+  TABLE_LIST tables;
+  bool not_used;
+  Open_tables_state backup;
+
+  // thd is 0x0 during boot of the server. Later it's !=0x0
+  if (!thd)
+    return;
+
+  thd->reset_n_backup_open_tables_state(&backup);
+  
+  bzero((char*) &tables, sizeof(tables));
+  tables.db= (char*) "mysql";
+  tables.table_name= tables.alias= (char*) "db";
+  tables.lock_type= TL_READ;
+
+  if (simple_open_n_lock_tables(thd, &tables))
+    sql_print_error("Cannot open mysql.db");
+  else
+  {
+    table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields,
+                     &mysql_db_table_last_check,ER_EVENT_CANNOT_LOAD_FROM_TABLE);                           
+    close_thread_tables(thd);
+  }
+
+  bzero((char*) &tables, sizeof(tables));
+  tables.db= (char*) "mysql";
+  tables.table_name= tables.alias= (char*) "user";
+  tables.lock_type= TL_READ;
+
+  if (simple_open_n_lock_tables(thd, &tables))
+    sql_print_error("Cannot open mysql.db");
+  else
+  {
+    if (tables.table->s->fields < 29 ||
+      strncmp(tables.table->field[29]->field_name,
+                STRING_WITH_LEN("Event_priv")))
+      sql_print_error("mysql.user has no `Event_priv` column at position 29");
+
+    close_thread_tables(thd);
+  }
+
+  thd->restore_backup_open_tables_state(&backup);
+}
+
+
+/*
+   Inits the scheduler. Called on server start and every time the scheduler
+   is started with switching the event_scheduler global variable to TRUE 
+
+   SYNOPSIS
+     init_events()
+          
+   NOTES
+    Inits the mutexes used by the scheduler. Done at server start.
+*/
+
 int
 init_events()
 {
@@ -91,6 +186,8 @@ init_events()
   DBUG_ENTER("init_events");
 
   DBUG_PRINT("info",("Starting events main thread"));
+  
+  evex_check_system_tables();
 
   evex_init_mutexes();
 
@@ -113,6 +210,16 @@ init_events()
 }
 
 
+/*
+   Cleans up scheduler memory. Called on server shutdown.
+
+   SYNOPSIS
+     shutdown_events()
+          
+   NOTES
+    Destroys the mutexes.
+*/
+
 void
 shutdown_events()
 {
@@ -129,6 +236,22 @@ shutdown_events()
 }
 
 
+/*
+   Inits an scheduler thread handler, both the main and a worker
+
+   SYNOPSIS
+     init_event_thread()
+       thd - the THD of the thread. Has to be allocated by the caller.
+          
+   NOTES
+      1. The host of the thead is my_localhost
+      2. thd->net is initted with NULL - no communication.
+  
+  Returns
+     0  - OK
+    -1  - Error
+*/
+
 static int
 init_event_thread(THD* thd)
 {
@@ -165,6 +288,22 @@ init_event_thread(THD* thd)
   DBUG_RETURN(0);
 }
 
+
+/*
+   The main scheduler thread. Inits the priority queue on start and
+   destroys it on thread shutdown. Forks child threads for every event
+   execution. Sleeps between thread forking and does not do a busy wait.
+
+   SYNOPSIS
+     event_executor_main() 
+       arg - unused
+          
+   NOTES
+      1. The host of the thead is my_localhost
+      2. thd->net is initted with NULL - no communication.
+  
+*/
+
 pthread_handler_t
 event_executor_main(void *arg)
 {
@@ -436,6 +575,15 @@ err_no_thd:
 }
 
 
+/*
+   Function that executes an event in a child thread. Setups the 
+   environment for the event execution and cleans after that.
+
+   SYNOPSIS
+     event_executor_worker()
+       arg - the event_timed object to be processed
+*/
+
 pthread_handler_t
 event_executor_worker(void *event_void)
 {
@@ -561,6 +709,24 @@ err_no_thd:
 }
 
 
+/*
+   Loads all ENABLED events from mysql.event into the prioritized
+   queue. Called during scheduler main thread initialization. Compiles
+   the events. Creates event_timed instances for every ENABLED event
+   from mysql.event.
+
+   SYNOPSIS
+     evex_load_events_from_db()
+       thd - Thread context. Used for memory allocation in some cases.
+     
+   RETURNS
+     0  - OK
+    -1  - Error
+    
+   NOTES
+     Reports the error to the console
+*/
+
 static int
 evex_load_events_from_db(THD *thd)
 {
@@ -647,7 +813,22 @@ end:
 }
 
 
-bool sys_var_event_executor::update(THD *thd, set_var *var)
+/*
+   The update method of the global variable event_scheduler.
+   If event_scheduler is switched from 0 to 1 then the scheduler main
+   thread is started.
+
+   SYNOPSIS
+     event_executor_worker()
+       thd - Thread context (unused)
+       car - the new value
+   
+   Returns
+     0 - OK (always)
+*/
+
+bool
+sys_var_event_executor::update(THD *thd, set_var *var)
 {
   // here start the thread if not running.
   DBUG_ENTER("sys_var_event_executor::update");
diff --git a/sql/event_priv.h b/sql/event_priv.h
index 7d1cdbcd26..16e415bc19 100644
--- a/sql/event_priv.h
+++ b/sql/event_priv.h
@@ -40,7 +40,6 @@ evex_db_find_event_aux(THD *thd, const LEX_STRING dbname,
 int 
 event_timed_compare_q(void *vptr, byte* a, byte *b);
 
-
 #define EXEC_QUEUE_QUEUE_NAME executing_queue
 #define EXEC_QUEUE_DARR_NAME evex_executing_queue
 
diff --git a/sql/event_timed.cc b/sql/event_timed.cc
index 28d21089b7..3b98d66497 100644
--- a/sql/event_timed.cc
+++ b/sql/event_timed.cc
@@ -116,7 +116,10 @@ event_timed::init_body(THD *thd)
   while (body.length && body_begin[body.length-1] == '\0')
     body.length--;
 
-  body.str= strmake_root(root, (char *)body_begin, body.length);
+  //the first is always space which I cannot skip in the parser
+  DBUG_ASSERT(*body_begin == ' ');
+  body.length--;
+  body.str= strmake_root(root, (char *)body_begin + 1, body.length);
 
   DBUG_VOID_RETURN;
 }
@@ -847,6 +850,15 @@ err:
 }
 
 
+/*
+  Set the internal last_executed TIME struct to now. NOW is the
+  time according to thd->query_start(), so the THD's clock.
+  
+  Synopsis
+    event_timed::drop()
+      thd - thread context
+*/
+
 void
 event_timed::mark_last_executed(THD *thd)
 {
@@ -864,7 +876,13 @@ event_timed::mark_last_executed(THD *thd)
 
 
 /*
-  Returns :
+  Drops the event
+  
+  Synopsis
+    event_timed::drop()
+      thd - thread context
+
+  RETURNS :
     0 - OK
    -1 - Cannot open mysql.event
    -2 - Cannot find the event in mysql.event (already deleted?)
@@ -894,6 +912,22 @@ event_timed::drop(THD *thd)
 }
 
 
+/*
+  Saves status and last_executed_at to the disk if changed.
+  
+  Synopsis
+    event_timed::drop()
+      thd - thread context
+
+  Returns :
+    0 - OK
+    SP_OPEN_TABLE_FAILED - Error while opening mysql.event for writing
+    EVEX_WRITE_ROW_FAILED - On error to write to disk
+   
+   others - return code from SE in case deletion of the event row
+            failed.
+*/
+
 bool
 event_timed::update_fields(THD *thd)
 {
@@ -951,40 +985,75 @@ done:
 }
 
 
-char *
-event_timed::get_show_create_event(THD *thd, uint32 *length)
+/*
+  Get SHOW CREATE EVENT as string
+  
+  thd  - Thread
+  buf  - String*, should be already allocated. CREATE EVENT goes inside.
+  
+  Returns:
+  0 - OK
+  1 - Error (for now if mysql.event has been tampered and MICROSECONDS
+      interval or derivative has been put there.
+*/
+
+int
+event_timed::get_create_event(THD *thd, String *buf)
 {
-  char *dst, *ret;
-  uint len, tmp_len;
-  DBUG_ENTER("get_show_create_event");
+  int multipl= 0;
+  char tmp_buff[128];
+  String expr_buf(tmp_buff, sizeof(tmp_buff), system_charset_info);
+  expr_buf.length(0);
+
+  DBUG_ENTER("get_create_event");
   DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
 
-  len = strlen("CREATE EVENT `") + dbname.length + strlen("`.`") + name.length +
-        strlen("` ON SCHEDULE EVERY 5 MINUTE DO ") + body.length;// + strlen(";");
-  
-  ret= dst= (char*) alloc_root(thd->mem_root, len + 1);
-  memcpy(dst, "CREATE EVENT `", tmp_len= strlen("CREATE EVENT `"));
-  dst+= tmp_len;
-  memcpy(dst, dbname.str, tmp_len=dbname.length);
-  dst+= tmp_len;
-  memcpy(dst, "`.`", tmp_len= strlen("`.`"));
-  dst+= tmp_len;
-  memcpy(dst, name.str, tmp_len= name.length);
-  dst+= tmp_len;
-  memcpy(dst, "` ON SCHEDULE EVERY 5 MINUTE DO ",
-         tmp_len= strlen("` ON SCHEDULE EVERY 5 MINUTE DO "));
-  dst+= tmp_len;
-
-  memcpy(dst, body.str, tmp_len= body.length);
-  dst+= tmp_len;
-//  memcpy(dst, ";", 1);
-//  ++dst;
-  *dst= '\0';
- 
-  *length= len;
-  
-  DBUG_PRINT("ret_info",("len=%d",*length));
-  DBUG_RETURN(ret);
+  if (expression &&
+      event_reconstruct_interval_expression(&expr_buf, interval, expression))
+      DBUG_RETURN(1);
+
+  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);
+
+  buf->append(STRING_WITH_LEN(" ON SCHEDULE "));
+  if (expression)
+  {
+    buf->append(STRING_WITH_LEN("EVERY "));
+    buf->append(expr_buf);
+  }
+  else
+  {
+    char dtime_buff[20*2+32];// +32 to make my_snprintf_{8bit|ucs2} happy
+    buf->append(STRING_WITH_LEN("AT '"));
+    /* 
+      pass the buffer and the second param tells fills the buffer and returns
+      the number of chars to copy
+    */
+    buf->append(dtime_buff, my_datetime_to_str(&execute_at, dtime_buff));
+    buf->append(STRING_WITH_LEN("'"));
+  }
+
+  if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+    buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
+  else
+    buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
+
+  if (status == MYSQL_EVENT_ENABLED)
+    buf->append(STRING_WITH_LEN("ENABLE"));
+  else
+    buf->append(STRING_WITH_LEN("DISABLE"));
+
+  if (comment.length)
+  {
+    buf->append(STRING_WITH_LEN(" COMMENT "));
+    append_unescaped(buf, comment.str, comment.length);
+  }
+  buf->append(STRING_WITH_LEN(" DO "));
+  buf->append(body.str, body.length);  
+
+  DBUG_RETURN(0);
 }
 
 
@@ -1045,13 +1114,21 @@ done:
 
 
 /*
+  Compiles an event before it's execution. Compiles the anonymous
+  sp_head object held by the event
+  
+  Synopsis
+    event_timed::compile()
+      thd      - thread context, used for memory allocation mostly
+      mem_root - if != NULL then this memory root is used for allocs
+                 instead of thd->mem_root   
+  
   Returns
                      0 - Success
     EVEX_COMPILE_ERROR - Error during compilation
 
 */
 
-
 int
 event_timed::compile(THD *thd, MEM_ROOT *mem_root)
 {
@@ -1064,9 +1141,13 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
   char *old_query;
   uint old_query_len;
   st_sp_chistics *p;
-  CHARSET_INFO *old_character_set_client, *old_collation_connection,
+  char create_buf[2048];
+  String show_create(create_buf, sizeof(create_buf), system_charset_info);
+  CHARSET_INFO *old_character_set_client,
+               *old_collation_connection,
                *old_character_set_results;
-
+  
+  show_create.length(0);
   old_character_set_client= thd->variables.character_set_client;
   old_character_set_results= thd->variables.character_set_results;
   old_collation_connection= thd->variables.collation_connection;
@@ -1089,7 +1170,11 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
   old_query= thd->query;
   old_db= thd->db;
   thd->db= dbname.str;
-  thd->query= get_show_create_event(thd, &thd->query_length);
+
+  get_create_event(thd, &show_create);
+
+  thd->query= show_create.c_ptr();
+  thd->query_length= show_create.length();
   DBUG_PRINT("event_timed::compile", ("query:%s",thd->query));
 
   thd->lex= &lex;
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 80910a8fd8..95b2ec739c 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5779,10 +5779,10 @@ ER_EVENT_OPEN_TABLE_FAILED
         eng "Failed to open mysql.event"
 ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
         eng "No datetime expression provided"
-ER_EVENT_COL_COUNT_DOESNT_MATCH
-        eng "Column count of %s.%s is wrong. Table probably corrupted"
+ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
+        eng "Column count of mysql.%s is wrong. Table probably corrupted. Expected %d, found %d."
 ER_EVENT_CANNOT_LOAD_FROM_TABLE
-        eng "Cannot load from mysql.event. Table probably corrupted"
+        eng "Cannot load from mysql.%s. Table probably corrupted. See error log."
 ER_EVENT_CANNOT_DELETE
         eng "Failed to delete the event from mysql.event"
 ER_EVENT_COMPILE_ERROR
@@ -5798,3 +5798,5 @@ ER_CANT_WRITE_LOCK_LOG_TABLE
         eng "You can't write-lock a log table. Only read access is possible."
 ER_CANT_READ_LOCK_LOG_TABLE
         eng "You can't use usual read lock with log tables. Try READ LOCAL instead."
+ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
+        eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use scripts/mysql_fix_privilege_tables"
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 8877d607e9..c0842c48e4 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -36,6 +36,122 @@
 
 #define FIRST_NON_YN_FIELD 26
 
+time_t mysql_db_table_last_check= 0L;
+
+TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
+  {
+    {(char *) STRING_WITH_LEN("Host")},            
+    {(char *) STRING_WITH_LEN("char(60)")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("Db")},            
+    {(char *) STRING_WITH_LEN("char(64)")},
+    {NULL, 0}
+  }, 
+  {
+    {(char *) STRING_WITH_LEN("User")},
+    {(char *) STRING_WITH_LEN("char(16)")},
+    {NULL, 0}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Select_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Insert_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Update_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Delete_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Create_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Drop_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Grant_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("References_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Index_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Alter_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Create_tmp_table_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Lock_tables_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Create_view_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Show_view_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Create_routine_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Alter_routine_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Execute_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Event_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  },
+  {
+    {(char *) STRING_WITH_LEN("Trigger_priv")},
+    {(char *) STRING_WITH_LEN("enum('N','Y')")},
+    {(char *) STRING_WITH_LEN("utf8")}
+  }
+};
+
+
 class acl_entry :public hash_filo_element
 {
 public:
@@ -435,14 +551,14 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
   while (!(read_record_info.read_record(&read_record_info)))
   {
     ACL_DB db;
-    update_hostname(&db.host,get_field(&mem, table->field[0]));
-    db.db=get_field(&mem, table->field[1]);
+    update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST]));
+    db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]);
     if (!db.db)
     {
       sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
       continue;
     }
-    db.user=get_field(&mem, table->field[2]);
+    db.user=get_field(&mem, table->field[MYSQL_DB_FIELD_USER]);
     if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
     {
       sql_print_warning("'db' entry '%s %s@%s' "
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index f42406ca1d..6cd61a77c4 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -129,6 +129,36 @@
 				     (((A) & ALTER_PROC_ACL) >> 23) | \
 				     (((A) & GRANT_ACL) >> 8))
 
+enum mysql_db_table_field
+{
+  MYSQL_DB_FIELD_HOST = 0,
+  MYSQL_DB_FIELD_DB,
+  MYSQL_DB_FIELD_USER,
+  MYSQL_DB_FIELD_SELECT_PRIV,
+  MYSQL_DB_FIELD_INSERT_PRIV,
+  MYSQL_DB_FIELD_UPDATE_PRIV,
+  MYSQL_DB_FIELD_DELETE_PRIV,
+  MYSQL_DB_FIELD_CREATE_PRIV,
+  MYSQL_DB_FIELD_DROP_PRIV,
+  MYSQL_DB_FIELD_GRANT_PRIV,
+  MYSQL_DB_FIELD_REFERENCES_PRIV,
+  MYSQL_DB_FIELD_INDEX_PRIV,
+  MYSQL_DB_FIELD_ALTER_PRIV,
+  MYSQL_DB_FIELD_CREATE_TMP_TABLE_PRIV,
+  MYSQL_DB_FIELD_LOCK_TABLES_PRIV,
+  MYSQL_DB_FIELD_CREATE_VIEW_PRIV,
+  MYSQL_DB_FIELD_SHOW_VIEW_PRIV,
+  MYSQL_DB_FIELD_CREATE_ROUTINE_PRIV,
+  MYSQL_DB_FIELD_ALTER_ROUTINE_PRIV,
+  MYSQL_DB_FIELD_EXECUTE_PRIV,
+  MYSQL_DB_FIELD_EVENT_PRIV,
+  MYSQL_DB_FIELD_TRIGGER_PRIV,
+  MYSQL_DB_FIELD_COUNT
+};
+
+extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
+extern time_t mysql_db_table_last_check;
+
 /* Classes */
 
 struct acl_host_and_ip
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ed7e7dfb68..1ea09b9ab1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3735,6 +3735,14 @@ end_with_restore_list:
   }
   case SQLCOM_SHOW_CREATE_EVENT:
   {
+    DBUG_ASSERT(lex->spname);
+    DBUG_ASSERT(lex->et);
+    if (! lex->spname->m_db.str)
+    {
+      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+      res= true;
+      break;
+    }
     if (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
                      is_schema_db(lex->spname->m_db.str)))
       break;
@@ -3744,8 +3752,7 @@ end_with_restore_list:
       my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
       goto error;
     }
-    /* TODO : Implement it */
-    send_ok(thd, 1);
+    res= evex_show_create_event(thd, lex->spname, lex->et->definer);
     break;
   }
   case SQLCOM_CREATE_FUNCTION:                  // UDF function
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 58f94887ef..620f8ab602 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3772,30 +3772,6 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
 }
 
 
-static LEX_STRING interval_type_to_name[] = {
-  {(char *) STRING_WITH_LEN("INTERVAL_YEAR")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_QUARTER")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_MONTH")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_DAY")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_HOUR")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_MINUTE")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_WEEK")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_SECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_MICROSECOND ")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_YEAR_MONTH")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_DAY_HOUR")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_DAY_MINUTE")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_DAY_SECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_HOUR_MINUTE")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_HOUR_SECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_MINUTE_SECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_DAY_MICROSECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_HOUR_MICROSECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_MINUTE_MICROSECOND")}, 
-  {(char *) STRING_WITH_LEN("INTERVAL_SECOND_MICROSECOND")}
-}; 
-
-
 static interval_type get_real_interval_type(interval_type i_type)
 {
   switch (i_type) {
@@ -3869,6 +3845,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
   sch_table->field[9]->set_null();
   if (et.expression)
   {
+    String show_str;
     //type
     sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
     //execute_at
@@ -3877,9 +3854,11 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
     sch_table->field[7]->set_notnull();
     sch_table->field[7]->store((longlong) et.expression);
     //interval_type
-    LEX_STRING *ival=&interval_type_to_name[get_real_interval_type(et.interval)];
+    if (event_reconstruct_interval_expression(&show_str, et.interval,
+                                              et.expression))
+      DBUG_RETURN(1);
     sch_table->field[8]->set_notnull();
-    sch_table->field[8]->store(ival->str, ival->length, scs);
+    sch_table->field[8]->store(show_str.c_ptr(), show_str.length(), scs);
     //starts & ends
     sch_table->field[10]->set_notnull();
     sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a86eccb493..3135c9ba21 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -8402,6 +8402,10 @@ show_param:
           {
             Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
             Lex->spname= $3;
+            Lex->et= new event_timed();
+            if (!Lex->et)
+              YYABORT;
+            Lex->et->init_definer(YYTHD);
           }
       ;
 
diff --git a/sql/table.cc b/sql/table.cc
index b912683d37..2cd039c9e0 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -343,9 +343,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
         allow to lock such tables for writing with any other tables (even with
         other system tables) and some privilege tables need this.
       */
-      if (!my_strcasecmp(system_charset_info, share->table_name.str, "proc")
-          || !my_strcasecmp(system_charset_info, share->table_name.str,
-                            "event"))
+      if (!my_strcasecmp(system_charset_info, share->table_name.str, "proc"))
         share->system_table= 1;
       else
       {
@@ -2296,6 +2294,144 @@ bool check_column_name(const char *name)
   return last_char_is_space || (uint) (name - start) > NAME_LEN;
 }
 
+
+/*
+  Checks whether a table is intact. Should be done *just* after the table has
+  been opened.
+  
+  Synopsis
+    table_check_intact()
+      table         - the table to check
+      table_f_count - expected number of columns in the table
+      table_def     - expected structure of the table (column name and type)
+    last_create_time- the table->file->create_time of the table in memory
+                      we have checked last time
+      error_num     - ER_XXXX from the error messages file. When 0 no error
+                      is sent to the client in case types does not match.
+                      If different col number either 
+                      ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE or 
+                      ER_COL_COUNT_DOESNT_MATCH_CORRUPTED is used
+
+  RETURNS
+    0   - OK
+    1   - There was an error
+*/
+
+my_bool
+table_check_intact(TABLE *table, uint table_f_count,
+                   TABLE_FIELD_W_TYPE *table_def, time_t *last_create_time,
+                   int error_num)
+{
+  uint i;
+  my_bool error= FALSE;
+  my_bool fields_diff_count;
+  DBUG_ENTER("table_check_intact");
+  DBUG_PRINT("info",("table=%s expected_count=%d",table->alias, table_f_count));
+  DBUG_PRINT("info",("last_create_time=%d", *last_create_time));
+  
+  if ((fields_diff_count= (table->s->fields != table_f_count)) ||
+      (*last_create_time != table->file->create_time))
+  {
+    DBUG_PRINT("info", ("I am suspecting, checking table"));
+    if (fields_diff_count)
+    {
+      // previous MySQL version
+      error= TRUE;
+      if (MYSQL_VERSION_ID > table->s->mysql_version)
+        my_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, MYF(0), table->alias,
+                 table_f_count, table->s->fields, table->s->mysql_version,
+                 MYSQL_VERSION_ID);
+      else if (MYSQL_VERSION_ID == table->s->mysql_version)
+        my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED,MYF(0), table->alias,
+                 table_f_count, table->s->fields);
+      else
+        /*
+          moving from newer mysql to older one -> let's say not an error but
+          will check the definition afterwards. If a column was added at the end
+          then we don't care much since it's not in the middle.
+        */
+        error= FALSE;
+    }
+    //definitely something has changed
+    char buffer[255];
+    for (i=0 ;i < table_f_count; ++i, ++table_def)
+    {      
+      Field *field= table->field[i];
+      String sql_type(buffer, sizeof(buffer), system_charset_info);
+      sql_type.length(0);
+      /*
+        name changes are not fatal, we use sequence numbers => no prob for us
+        but this can show tampered table or broken table.
+      */
+      if (!fields_diff_count || i < table->s->fields)
+      {
+        if (strncmp(field->field_name, table_def->name.str,
+                                       table_def->name.length))
+        {
+          sql_print_error("(%s) Expected field %s at position %d, found %s",
+                          table->alias, table_def->name.str, i,
+                          field->field_name);
+        }
+                        
+        /*
+          IF the type does not match than something is really wrong
+          Check up to length - 1. Why?
+          1. datetime -> datetim -> the same
+          2. int(11) -> int(11  -> the same
+          3. set('one','two') -> set('one','two'  
+             so for sets if the same prefix is there it's ok if more are
+             added as part of the set. The same is valid for enum. So a new
+             table running on a old server will be valid.
+        */ 
+        field->sql_type(sql_type);
+        if (strncmp(sql_type.c_ptr(), table_def->type.str,
+                    table_def->type.length - 1))
+        {
+          sql_print_error("(%s) Expected field %s at position %d to have type "
+                          "%s, found %s", table->alias, table_def->name.str,
+                          i, table_def->type.str, sql_type.c_ptr()); 
+          error= TRUE;
+        }
+        else if (table_def->cset.str && !field->has_charset())
+        {
+          sql_print_error("(%s) Expected field %s at position %d to have "
+                          "character set '%s' but found no such", table->alias,
+                          table_def->name.str, i, table_def->cset.str);        
+          error= TRUE;
+        }
+        else if (table_def->cset.str && 
+                 strcmp(field->charset()->csname, table_def->cset.str))
+        {
+          sql_print_error("(%s) Expected field %s at position %d to have "
+                          "character set '%s' but found '%s'", table->alias,
+                          table_def->name.str, i, table_def->cset.str,
+                          field->charset()->csname);
+          error= TRUE;
+        }
+      }
+      else
+      {
+        sql_print_error("(%s) Expected field %s at position %d to have type %s "
+                        " but no field found.", table_def->name.str,
+                        table_def->name.str, i, table_def->type.str);
+        error= TRUE;        
+      }
+    }
+    if (!error)
+      *last_create_time= table->file->create_time;
+    else if (!fields_diff_count && error_num)
+      my_error(error_num,MYF(0), table->alias, table_f_count, table->s->fields);
+  }
+  else
+  {
+    DBUG_PRINT("info", ("Table seems ok without through checking."));
+    *last_create_time= table->file->create_time;
+  }
+   
+  DBUG_RETURN(error);  
+}
+
+
 /*
   Create Item_field for each column in the table.
 
diff --git a/sql/table.h b/sql/table.h
index 213310a51d..5305c9af00 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -864,4 +864,15 @@ typedef struct st_open_table_list{
   uint32 in_use,locked;
 } OPEN_TABLE_LIST;
 
+typedef struct st_table_field_w_type
+{
+  LEX_STRING name;
+  LEX_STRING type;
+  LEX_STRING cset;
+} TABLE_FIELD_W_TYPE;
+
 
+my_bool
+table_check_intact(TABLE *table, uint table_f_count,
+                   TABLE_FIELD_W_TYPE *table_def, time_t *last_create_time,
+                   int error_num);
-- 
2.30.9