Skip to content

Commit bc73afe

Browse files
committed
MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }
Follow-up to fix the issue with starting server on a data dictionary with broken table mysql.event or on its previous version without columns required for storing metadata about triggers.
1 parent a5f211a commit bc73afe

17 files changed

Lines changed: 419 additions & 155 deletions

mysql-test/main/trigger_system.result

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
call mtr.add_suppression('Column count of mysql.event is wrong.');
2+
call mtr.add_suppression('Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.');
3+
call mtr.add_suppression('An error occurred when loading data from the table mysql.event. System triggers not loaded');
4+
call mtr.add_suppression('Aborting');
5+
call mtr.add_suppression('Incorrect definition of table mysql.event: expected column');
16
#
27
# MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }
38
#
@@ -139,3 +144,39 @@ CREATE EVENT trg1 ON SCHEDULE EVERY 1 YEAR DO SET @aaa=1;
139144
ERROR HY000: Trigger with the same name 'trg1' already exists
140145
# Clean up
141146
DROP TRIGGER trg1;
147+
#
148+
# Test 9: Check that server can operate on database with
149+
# broken table mysql.event.
150+
CREATE TRIGGER trg1 AFTER STARTUP SET @bbb=1;
151+
# Backup the mysql.event table
152+
CREATE TABLE event_copy LIKE mysql.event;
153+
INSERT INTO event_copy SELECT * FROM mysql.event;
154+
# Drop column 'kind' in the table mysql.event to simulate a failure on
155+
# loading triggers metadata from the table mysql.event
156+
ALTER TABLE mysql.event DROP COLUMN kind;
157+
# Shutdown server and restart it to see how it handle broken
158+
# table mysql.event
159+
# Restart server. Expect start up failure
160+
# Force server start up even on broken data dictionary.
161+
# restart: --skip-grant-tables
162+
# Restore original mysql.event from backup
163+
DROP TABLE mysql.event;
164+
RENAME TABLE event_copy TO mysql.event;
165+
# Restart server. Should be successful.
166+
# restart
167+
# Clean up
168+
DROP TRIGGER trg1;
169+
#
170+
# Test 10: Check that server can be started up on the data dictionary
171+
# having the table mysql.event from previous version of
172+
# server (missing mandatory columns for support of system triggers)
173+
#
174+
RENAME TABLE mysql.event TO mysql.ev_bk;
175+
# Copy event table's files from previous server version (12.3)
176+
# that doesn't contain columns required for system triggers support
177+
# restart
178+
CREATE TRIGGER ev1 AFTER STARTUP SET @bbb=1;
179+
ERROR HY000: The table mysql.event doesn't contain all mandatory columns required for support of system triggers. Operations with system triggers is disabled.
180+
DROP TABLE mysql.event;
181+
RENAME TABLE mysql.ev_bk TO mysql.event;
182+
# End of Test 10.

mysql-test/main/trigger_system.test

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
--source include/count_sessions.inc
44

5+
call mtr.add_suppression('Column count of mysql.event is wrong.');
6+
call mtr.add_suppression('Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.');
7+
call mtr.add_suppression('An error occurred when loading data from the table mysql.event. System triggers not loaded');
8+
call mtr.add_suppression('Aborting');
9+
call mtr.add_suppression('Incorrect definition of table mysql.event: expected column');
10+
511
--echo #
612
--echo # MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }
713
--echo #
@@ -149,3 +155,67 @@ CREATE TRIGGER trg1 AFTER STARTUP SET @bbb=1;
149155
CREATE EVENT trg1 ON SCHEDULE EVERY 1 YEAR DO SET @aaa=1;
150156
--echo # Clean up
151157
DROP TRIGGER trg1;
158+
159+
--echo #
160+
--echo # Test 9: Check that server can operate on database with
161+
--echo # broken table mysql.event.
162+
CREATE TRIGGER trg1 AFTER STARTUP SET @bbb=1;
163+
164+
--echo # Backup the mysql.event table
165+
CREATE TABLE event_copy LIKE mysql.event;
166+
INSERT INTO event_copy SELECT * FROM mysql.event;
167+
168+
--echo # Drop column 'kind' in the table mysql.event to simulate a failure on
169+
--echo # loading triggers metadata from the table mysql.event
170+
ALTER TABLE mysql.event DROP COLUMN kind;
171+
172+
--echo # Shutdown server and restart it to see how it handle broken
173+
--echo # table mysql.event
174+
--source include/shutdown_mysqld.inc
175+
176+
--echo # Restart server. Expect start up failure
177+
--error 1
178+
--exec $MYSQLD_LAST_CMD
179+
180+
--echo # Force server start up even on broken data dictionary.
181+
--let $restart_parameters=--skip-grant-tables
182+
--source include/start_mysqld.inc
183+
184+
--echo # Restore original mysql.event from backup
185+
DROP TABLE mysql.event;
186+
RENAME TABLE event_copy TO mysql.event;
187+
188+
--echo # Restart server. Should be successful.
189+
--let $restart_parameters=
190+
--source include/restart_mysqld.inc
191+
192+
--echo # Clean up
193+
DROP TRIGGER trg1;
194+
195+
--echo #
196+
--echo # Test 10: Check that server can be started up on the data dictionary
197+
--echo # having the table mysql.event from previous version of
198+
--echo # server (missing mandatory columns for support of system triggers)
199+
--echo #
200+
RENAME TABLE mysql.event TO mysql.ev_bk;
201+
--let $MYSQLD_DATADIR= `select @@datadir`
202+
203+
--source include/shutdown_mysqld.inc
204+
205+
--echo # Copy event table's files from previous server version (12.3)
206+
--echo # that doesn't contain columns required for system triggers support
207+
--copy_file $MYSQL_TEST_DIR/std_data/mdev-30645-event.MAI $MYSQLD_DATADIR/mysql/event.MAI
208+
--copy_file $MYSQL_TEST_DIR/std_data/mdev-30645-event.MAD $MYSQLD_DATADIR/mysql/event.MAD
209+
--copy_file $MYSQL_TEST_DIR/std_data/mdev-30645-event.frm $MYSQLD_DATADIR/mysql/event.frm
210+
211+
#--let $restart_parameters=--skip-grant-tables
212+
--source include/start_mysqld.inc
213+
214+
--error ER_SYSTEM_TRG_DISABLED
215+
CREATE TRIGGER ev1 AFTER STARTUP SET @bbb=1;
216+
217+
# back to mariadb default
218+
DROP TABLE mysql.event;
219+
RENAME TABLE mysql.ev_bk TO mysql.event;
220+
221+
--echo # End of Test 10.
8 KB
Binary file not shown.
8 KB
Binary file not shown.
4.57 KB
Binary file not shown.

mysql-test/suite/events/events_restart.result

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,42 @@ alter table mysql.event
2020
change column body body longtext character set utf8 collate utf8_bin;
2121
# Now we restart the server
2222
call mtr.add_suppression("Incorrect definition of table mysql.event:.*");
23-
# restart
23+
# Turn the option --skip-grant-tables on in order to be able
24+
# to start server on broken mysql.event table
25+
# restart: --skip-grant-tables
2426
use events_test;
2527
select @@event_scheduler;
2628
@@event_scheduler
27-
OFF
29+
DISABLED
2830
show events;
2931
ERROR HY000: Cannot proceed, because event scheduler is disabled
3032
select event_name from information_schema.events;
31-
ERROR HY000: Cannot proceed, because event scheduler is disabled
33+
event_name
3234
show create event intact_check;
3335
ERROR HY000: Cannot proceed, because event scheduler is disabled
3436
drop event no_such_event;
35-
ERROR HY000: Cannot proceed, because event scheduler is disabled
37+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
3638
create event intact_check_1 on schedule every 5 hour do select 5;
37-
ERROR HY000: Cannot proceed, because event scheduler is disabled
39+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
3840
alter event intact_check_1 on schedule every 8 hour do select 8;
39-
ERROR HY000: Cannot proceed, because event scheduler is disabled
41+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
4042
alter event intact_check_1 rename to intact_check_2;
41-
ERROR HY000: Cannot proceed, because event scheduler is disabled
43+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
4244
drop event intact_check_1;
43-
ERROR HY000: Cannot proceed, because event scheduler is disabled
45+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
4446
drop event intact_check_2;
45-
ERROR HY000: Cannot proceed, because event scheduler is disabled
47+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
4648
drop event intact_check;
47-
ERROR HY000: Cannot proceed, because event scheduler is disabled
49+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
50+
# Since server is started with --skip-grant-tables option the following
51+
# two statements be failed with the error ER_OPTION_PREVENTS_STATEMENT
4852
set global event_scheduler=on;
49-
ERROR HY000: Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.
53+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
5054
set global event_scheduler=off;
51-
ERROR HY000: Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.
55+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
5256
show variables like 'event_scheduler';
5357
Variable_name Value
54-
event_scheduler OFF
58+
event_scheduler DISABLED
5559
# Make sure that we still can create and drop databases,
5660
# and no warnings are produced.
5761
drop database if exists mysqltest_database_not_exists;
@@ -64,23 +68,9 @@ Error 1545 Failed to open mysql.event
6468
# Restore the original mysql.event table
6569
drop table mysql.event;
6670
rename table event_like to mysql.event;
67-
# check that we can now enable events without restart
68-
set global event_scheduler=original;
69-
Warnings:
70-
Note 1408 Event Scheduler: Loaded 3 events
71-
select @@global.event_scheduler;
72-
@@global.event_scheduler
73-
ON
74-
set global event_scheduler=on;
75-
select @@global.event_scheduler;
76-
@@global.event_scheduler
77-
ON
78-
show events;
79-
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
80-
events_test abc1 root@localhost SYSTEM RECURRING # 1 SECOND # # ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
81-
events_test abc2 root@localhost SYSTEM RECURRING # 1 SECOND # # ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
82-
events_test abc3 root@localhost SYSTEM RECURRING # 1 SECOND # # ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
8371
# Now let's restart the server again
72+
# clean the flag '--skip-grant-tables' previously set
73+
# to start server on broken mysql.event table
8474
# restart
8575
use events_test;
8676
select @@event_scheduler;

mysql-test/suite/events/events_restart.test

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
call mtr.add_suppression('Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted');
55
call mtr.add_suppression('Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler');
66
call mtr.add_suppression('Event Scheduler.*shutdown.*');
7+
call mtr.add_suppression('Event Scheduler will not function when starting with --skip-grant-tables');
78
--enable_query_log
89

910
let $collation_server=`select @@collation_server`;
@@ -47,6 +48,10 @@ alter table mysql.event
4748
--echo # Now we restart the server
4849

4950
call mtr.add_suppression("Incorrect definition of table mysql.event:.*");
51+
52+
--echo # Turn the option --skip-grant-tables on in order to be able
53+
--echo # to start server on broken mysql.event table
54+
--let $restart_parameters=--skip-grant-tables
5055
--source include/restart_mysqld.inc
5156

5257
use events_test;
@@ -55,27 +60,28 @@ select @@event_scheduler;
5560
# Try various Event Scheduler operation and check the output.
5661
--error ER_EVENTS_DB_ERROR
5762
show events;
58-
--error ER_EVENTS_DB_ERROR
5963
select event_name from information_schema.events;
6064
--error ER_EVENTS_DB_ERROR
6165
show create event intact_check;
62-
--error ER_EVENTS_DB_ERROR
66+
--error ER_OPTION_PREVENTS_STATEMENT
6367
drop event no_such_event;
64-
--error ER_EVENTS_DB_ERROR
68+
--error ER_OPTION_PREVENTS_STATEMENT
6569
create event intact_check_1 on schedule every 5 hour do select 5;
66-
--error ER_EVENTS_DB_ERROR
70+
--error ER_OPTION_PREVENTS_STATEMENT
6771
alter event intact_check_1 on schedule every 8 hour do select 8;
68-
--error ER_EVENTS_DB_ERROR
72+
--error ER_OPTION_PREVENTS_STATEMENT
6973
alter event intact_check_1 rename to intact_check_2;
70-
--error ER_EVENTS_DB_ERROR
74+
--error ER_OPTION_PREVENTS_STATEMENT
7175
drop event intact_check_1;
72-
--error ER_EVENTS_DB_ERROR
76+
--error ER_OPTION_PREVENTS_STATEMENT
7377
drop event intact_check_2;
74-
--error ER_EVENTS_DB_ERROR
78+
--error ER_OPTION_PREVENTS_STATEMENT
7579
drop event intact_check;
76-
--error ER_STARTUP
80+
--echo # Since server is started with --skip-grant-tables option the following
81+
--echo # two statements be failed with the error ER_OPTION_PREVENTS_STATEMENT
82+
--error ER_OPTION_PREVENTS_STATEMENT
7783
set global event_scheduler=on;
78-
--error ER_STARTUP
84+
--error ER_OPTION_PREVENTS_STATEMENT
7985
set global event_scheduler=off;
8086
show variables like 'event_scheduler';
8187
--echo # Make sure that we still can create and drop databases,
@@ -87,18 +93,11 @@ drop database mysqltest_db1;
8793
drop table mysql.event;
8894
rename table event_like to mysql.event;
8995

90-
--echo # check that we can now enable events without restart
91-
set global event_scheduler=original;
92-
select @@global.event_scheduler;
93-
set global event_scheduler=on;
94-
select @@global.event_scheduler;
95-
--sorted_result
96-
--replace_column 6 # 9 # 10 #
97-
--replace_result $collation_server latin1_swedish_ci
98-
show events;
99-
10096
--echo # Now let's restart the server again
10197

98+
--echo # clean the flag '--skip-grant-tables' previously set
99+
--echo # to start server on broken mysql.event table
100+
--let $restart_parameters=
102101
--source include/restart_mysqld.inc
103102

104103
# We need this file primarily to make sure that the scheduler is restarted

sql/event_common.cc

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <my_alloc.h> // MEM_ROOT
44
#include "event_common.h"
55
#include "event_db_repository.h" // enum enum_events_table_field
6+
#include "log.h" // sql_print_warning
67
#include "sp.h" // load_charset
78
#include "sql_base.h" // MYSQL_LOCK_IGNORE_TIMEOUT
89
#include "sql_class.h" // THD
@@ -255,6 +256,8 @@ Event_db_repository_common::MYSQL_EVENT_NAME= { STRING_WITH_LEN("event") };
255256
const TABLE_FIELD_DEF
256257
Event_db_repository_common::event_table_def= {ET_FIELD_COUNT, event_table_fields, 0, (uint*) 0};
257258

259+
static const TABLE_FIELD_DEF
260+
event_table_def_wo_trg= {ET_FIELD_COUNT - 3, event_table_fields, 0, (uint*) 0};
258261

259262
/**
260263
Open mysql.event table for read.
@@ -281,7 +284,8 @@ Event_db_repository_common::event_table_def= {ET_FIELD_COUNT, event_table_fields
281284
bool
282285
Event_db_repository_common::open_event_table(THD *thd,
283286
enum thr_lock_type lock_type,
284-
TABLE **table)
287+
TABLE **table,
288+
bool *enable_sys_trg)
285289
{
286290
TABLE_LIST tables;
287291
DBUG_ENTER("Event_db_repository::open_event_table");
@@ -296,15 +300,50 @@ Event_db_repository_common::open_event_table(THD *thd,
296300
/* NOTE: &tables pointer will be invalid after return */
297301
tables.table->pos_in_table_list= NULL;
298302

299-
if (table_intact.check(*table, &event_table_def))
303+
/*
304+
First, check that the most probable case: the table mysql.event
305+
contains all columns required for support of system triggers, that is
306+
in presence all columns of the table mysql.event version 12.3 plus
307+
extra columns added for storing system triggers metadata
308+
*/
309+
if (!table_intact.check(*table, &event_table_def))
300310
{
301-
thd->commit_whole_transaction_and_close_tables();
302-
*table= 0; // Table is now closed
303-
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
304-
DBUG_RETURN(TRUE);
311+
if (enable_sys_trg)
312+
*enable_sys_trg= true;
313+
314+
DBUG_RETURN(false);
315+
}
316+
317+
if (enable_sys_trg != nullptr)
318+
{
319+
/*
320+
Disable system triggers since the base structure of the table
321+
mysql.event misses mandatory columns
322+
*/
323+
*enable_sys_trg= false;
324+
my_error(ER_SYSTEM_TRG_DISABLED, MYF(ME_WARNING));
325+
}
326+
327+
/*
328+
Check that the core subset of mysql.event table's columns are present.
329+
*/
330+
if (!table_intact.check(*table, &event_table_def_wo_trg))
331+
{
332+
/*
333+
Since the base structure of the table mysql.event contains
334+
all columns required for running events, return success.
335+
336+
@note: Intentionally don't close the table since missing extra
337+
columns required for system triggers support ins't treated
338+
as error condition.
339+
*/
340+
DBUG_RETURN(false);
305341
}
306342

307-
DBUG_RETURN(FALSE);
343+
thd->commit_whole_transaction_and_close_tables();
344+
*table= 0; // Table is now closed
345+
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
346+
DBUG_RETURN(true);
308347
}
309348

310349

@@ -341,7 +380,12 @@ Event_db_repository_common::check_system_tables(THD *thd)
341380
else
342381
{
343382
if (table_intact.check(tables.table, &event_table_def))
344-
ret= 1;
383+
{
384+
if (table_intact.check(tables.table, &event_table_def_wo_trg))
385+
ret= 1;
386+
else
387+
ret= 0;
388+
}
345389
close_mysql_tables(thd);
346390
}
347391

sql/event_common.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ class Event_db_repository_common
5050
{
5151
public:
5252
static bool open_event_table(THD *thd, enum thr_lock_type lock_type,
53-
TABLE **table);
53+
TABLE **table,
54+
bool *enable_sys_trg= nullptr);
5455

5556
static bool check_system_tables(THD *thd);
5657

0 commit comments

Comments
 (0)