Skip to content

Commit 6507eb9

Browse files
committed
MDEV-30645: CREATE TRIGGER FOR { STARTUP | SHUTDOWN }
Follow-up to fix building with EMBEDDED server. Since support of events isn't compiled in for embedded server but some stuff from implementation of events is used for support of triggers, common source code used both for events and triggers was extracted into the separate files event_common.cc/event_common.h
1 parent e92f735 commit 6507eb9

10 files changed

Lines changed: 456 additions & 409 deletions

libmysqld/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
166166
../sql/opt_hints.cc ../sql/opt_hints.h
167167
../sql/opt_trace_ddl_info.cc ../sql/opt_trace_ddl_info.h
168168
../sql/sql_path.cc
169+
../sql/sql_sys_or_ddl_trigger.cc
170+
../sql/event_common.cc
169171
${GEN_SOURCES}
170172
${MYSYS_LIBWRAP_SOURCE}
171173
)

sql/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ SET (SQL_SOURCE
147147
sql_time.cc tztime.cc unireg.cc item_xmlfunc.cc
148148
uniques.cc
149149
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc
150-
event_data_objects.cc
150+
event_data_objects.cc event_common.cc
151151
event_queue.cc event_db_repository.cc
152152
events.cc ../sql-common/my_user.c
153153
partition_info.cc rpl_utility.cc rpl_utility_server.cc

sql/event_common.cc

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */
2+
3+
#include <my_alloc.h> // MEM_ROOT
4+
#include "event_common.h"
5+
#include "event_db_repository.h" // enum enum_events_table_field
6+
#include "sp.h" // load_charset
7+
#include "sql_base.h" // MYSQL_LOCK_IGNORE_TIMEOUT
8+
#include "sql_class.h" // THD
9+
#include "sql_db.h" // get_default_db_collation
10+
11+
/**************************************************************************
12+
Event_creation_ctx implementation.
13+
**************************************************************************/
14+
15+
bool
16+
Event_creation_ctx::load_from_db(THD *thd,
17+
MEM_ROOT *event_mem_root,
18+
const char *db_name,
19+
const char *event_name,
20+
TABLE *event_tbl,
21+
Stored_program_creation_ctx **ctx)
22+
{
23+
/* Load character set/collation attributes. */
24+
25+
CHARSET_INFO *client_cs;
26+
CHARSET_INFO *connection_cl;
27+
CHARSET_INFO *db_cl;
28+
29+
bool invalid_creation_ctx= false;
30+
31+
if (load_charset(thd, event_mem_root,
32+
event_tbl->field[ET_FIELD_CHARACTER_SET_CLIENT],
33+
thd->variables.character_set_client,
34+
&client_cs))
35+
{
36+
sql_print_warning("Event '%s'.'%s': invalid value "
37+
"in column mysql.event.character_set_client.",
38+
(const char *) db_name,
39+
(const char *) event_name);
40+
41+
invalid_creation_ctx= true;
42+
}
43+
44+
if (load_collation(thd, event_mem_root,
45+
event_tbl->field[ET_FIELD_COLLATION_CONNECTION],
46+
thd->variables.collation_connection,
47+
&connection_cl))
48+
{
49+
sql_print_warning("Event '%s'.'%s': invalid value "
50+
"in column mysql.event.collation_connection.",
51+
(const char *) db_name,
52+
(const char *) event_name);
53+
54+
invalid_creation_ctx= true;
55+
}
56+
57+
if (load_collation(thd, event_mem_root,
58+
event_tbl->field[ET_FIELD_DB_COLLATION],
59+
NULL,
60+
&db_cl))
61+
{
62+
sql_print_warning("Event '%s'.'%s': invalid value "
63+
"in column mysql.event.db_collation.",
64+
(const char *) db_name,
65+
(const char *) event_name);
66+
67+
invalid_creation_ctx= true;
68+
}
69+
70+
/*
71+
If we failed to resolve the database collation, load the default one
72+
from the disk.
73+
*/
74+
75+
if (!db_cl)
76+
db_cl= get_default_db_collation(thd, db_name);
77+
78+
/* Create the context. */
79+
80+
*ctx= new Event_creation_ctx(client_cs, connection_cl, db_cl);
81+
82+
return invalid_creation_ctx;
83+
}
84+
85+
86+
/**
87+
Wrapper around Event_creation_ctx::load_from_db() to make it visible
88+
from sql_sys_or_ddl_triggers()
89+
*/
90+
91+
bool
92+
load_creation_context_for_sys_trg(THD *thd,
93+
MEM_ROOT *event_mem_root,
94+
const char *db_name,
95+
const char *event_name,
96+
TABLE *event_tbl,
97+
Stored_program_creation_ctx **ctx)
98+
{
99+
return Event_creation_ctx::load_from_db(thd, event_mem_root,
100+
db_name,
101+
event_name,
102+
event_tbl,
103+
ctx);
104+
}
105+
106+
static const
107+
TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
108+
{
109+
{
110+
{ STRING_WITH_LEN("db") },
111+
{ STRING_WITH_LEN("char(64)") },
112+
{ STRING_WITH_LEN("utf8mb") }
113+
},
114+
{
115+
{ STRING_WITH_LEN("name") },
116+
{ STRING_WITH_LEN("char(64)") },
117+
{ STRING_WITH_LEN("utf8mb") }
118+
},
119+
{
120+
{ STRING_WITH_LEN("body") },
121+
{ STRING_WITH_LEN("longblob") },
122+
{NULL, 0}
123+
},
124+
{
125+
{ STRING_WITH_LEN("definer") },
126+
{ STRING_WITH_LEN("varchar(") },
127+
{ STRING_WITH_LEN("utf8mb") }
128+
},
129+
{
130+
{ STRING_WITH_LEN("execute_at") },
131+
{ STRING_WITH_LEN("datetime") },
132+
{NULL, 0}
133+
},
134+
{
135+
{ STRING_WITH_LEN("interval_value") },
136+
{ STRING_WITH_LEN("int(11)") },
137+
{NULL, 0}
138+
},
139+
{
140+
{ STRING_WITH_LEN("interval_field") },
141+
{ STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
142+
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
143+
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
144+
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
145+
"'SECOND_MICROSECOND')") },
146+
{NULL, 0}
147+
},
148+
{
149+
{ STRING_WITH_LEN("created") },
150+
{ STRING_WITH_LEN("timestamp") },
151+
{NULL, 0}
152+
},
153+
{
154+
{ STRING_WITH_LEN("modified") },
155+
{ STRING_WITH_LEN("timestamp") },
156+
{NULL, 0}
157+
},
158+
{
159+
{ STRING_WITH_LEN("last_executed") },
160+
{ STRING_WITH_LEN("datetime") },
161+
{NULL, 0}
162+
},
163+
{
164+
{ STRING_WITH_LEN("starts") },
165+
{ STRING_WITH_LEN("datetime") },
166+
{NULL, 0}
167+
},
168+
{
169+
{ STRING_WITH_LEN("ends") },
170+
{ STRING_WITH_LEN("datetime") },
171+
{NULL, 0}
172+
},
173+
{
174+
{ STRING_WITH_LEN("status") },
175+
{ STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')") },
176+
{NULL, 0}
177+
},
178+
{
179+
{ STRING_WITH_LEN("on_completion") },
180+
{ STRING_WITH_LEN("enum('DROP','PRESERVE')") },
181+
{NULL, 0}
182+
},
183+
{
184+
{ STRING_WITH_LEN("sql_mode") },
185+
{ STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
186+
"'IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY',"
187+
"'NO_UNSIGNED_SUBTRACTION',"
188+
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
189+
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
190+
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
191+
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
192+
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
193+
"'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH',"
194+
"'EMPTY_STRING_IS_NULL','SIMULTANEOUS_ASSIGNMENT')") },
195+
{NULL, 0}
196+
},
197+
{
198+
{ STRING_WITH_LEN("comment") },
199+
{ STRING_WITH_LEN("char(64)") },
200+
{ STRING_WITH_LEN("utf8mb") }
201+
},
202+
{
203+
{ STRING_WITH_LEN("originator") },
204+
{ STRING_WITH_LEN("int(10)") },
205+
{NULL, 0}
206+
},
207+
{
208+
{ STRING_WITH_LEN("time_zone") },
209+
{ STRING_WITH_LEN("char(64)") },
210+
{ STRING_WITH_LEN("latin1") }
211+
},
212+
{
213+
{ STRING_WITH_LEN("character_set_client") },
214+
{ STRING_WITH_LEN("char(32)") },
215+
{ STRING_WITH_LEN("utf8mb") }
216+
},
217+
{
218+
{ STRING_WITH_LEN("collation_connection") },
219+
{ STRING_WITH_LEN("char(") },
220+
{ STRING_WITH_LEN("utf8mb") }
221+
},
222+
{
223+
{ STRING_WITH_LEN("db_collation") },
224+
{ STRING_WITH_LEN("char(") },
225+
{ STRING_WITH_LEN("utf8mb") }
226+
},
227+
{
228+
{ STRING_WITH_LEN("body_utf8") },
229+
{ STRING_WITH_LEN("longblob") },
230+
{ NULL, 0 }
231+
},
232+
{
233+
{ STRING_WITH_LEN("kind") },
234+
{ STRING_WITH_LEN("set('SCHEDULE','STARTUP','SHUTDOWN',"
235+
"'LOGON','LOGOFF','DDL')") },
236+
{ NULL, 0 }
237+
},
238+
{
239+
{ STRING_WITH_LEN("when") },
240+
{ STRING_WITH_LEN("enum('BEFORE','AFTER')") },
241+
{ NULL, 0 }
242+
},
243+
{
244+
{ STRING_WITH_LEN("ddl_type") },
245+
{ STRING_WITH_LEN("set('CREATE','ALTER','DROP','TRUNCATE',"
246+
"'ANALYZE','RENAME','GRANT','REVOKE')") },
247+
{ NULL, 0 }
248+
}
249+
};
250+
251+
LEX_CSTRING
252+
Event_db_repository_common::MYSQL_EVENT_NAME= { STRING_WITH_LEN("event") };
253+
254+
255+
const TABLE_FIELD_DEF
256+
Event_db_repository_common::event_table_def= {ET_FIELD_COUNT, event_table_fields, 0, (uint*) 0};
257+
258+
259+
/**
260+
Open mysql.event table for read.
261+
262+
It's assumed that the caller knows what they are doing:
263+
- whether it was necessary to reset-and-backup the open tables state
264+
- whether the requested lock does not lead to a deadlock
265+
- whether this open mode would work under LOCK TABLES, or inside a
266+
stored function or trigger.
267+
268+
Note that if the table can't be locked successfully this operation will
269+
close it. Therefore it provides guarantee that it either opens and locks
270+
table or fails without leaving any tables open.
271+
272+
@param[in] thd Thread context
273+
@param[in] lock_type How to lock the table
274+
@param[out] table We will store the open table here
275+
276+
@retval TRUE open and lock failed - an error message is pushed into the
277+
stack
278+
@retval FALSE success
279+
*/
280+
281+
bool
282+
Event_db_repository_common::open_event_table(THD *thd,
283+
enum thr_lock_type lock_type,
284+
TABLE **table)
285+
{
286+
TABLE_LIST tables;
287+
DBUG_ENTER("Event_db_repository::open_event_table");
288+
289+
tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_EVENT_NAME, 0, lock_type);
290+
291+
if (open_and_lock_tables(thd, &tables, false, MYSQL_LOCK_IGNORE_TIMEOUT))
292+
DBUG_RETURN(true);
293+
294+
*table= tables.table;
295+
tables.table->use_all_columns();
296+
/* NOTE: &tables pointer will be invalid after return */
297+
tables.table->pos_in_table_list= NULL;
298+
299+
if (table_intact.check(*table, &event_table_def))
300+
{
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(tru);
305+
}
306+
307+
DBUG_RETURN(false);
308+
}
309+
310+
311+
/**
312+
Open mysql.db, mysql.user and mysql.event and check whether:
313+
- mysql.db exists and is up to date (or from a newer version of MySQL),
314+
- mysql.user has column Event_priv at an expected position,
315+
- mysql.event exists and is up to date (or from a newer version of
316+
MySQL)
317+
318+
This function is called only when the server is started.
319+
@pre The passed in thread handle has no open tables.
320+
321+
@retval FALSE OK
322+
@retval TRUE Error, an error message is output to the error log.
323+
*/
324+
325+
bool
326+
Event_db_repository_common::check_system_tables(THD *thd)
327+
{
328+
TABLE_LIST tables;
329+
bool ret= false;
330+
DBUG_ENTER("Event_db_repository::check_system_tables");
331+
DBUG_PRINT("enter", ("thd: %p", thd));
332+
333+
/* Check mysql.event */
334+
tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_EVENT_NAME, 0, TL_READ);
335+
336+
if (open_and_lock_tables(thd, &tables, false, MYSQL_LOCK_IGNORE_TIMEOUT))
337+
{
338+
ret= true;
339+
sql_print_error("Cannot open mysql.event");
340+
}
341+
else
342+
{
343+
if (table_intact.check(tables.table, &event_table_def))
344+
ret= true;
345+
close_mysql_tables(thd);
346+
}
347+
348+
DBUG_RETURN(ret);
349+
}
350+
351+
Table_check_intact_log_error Event_db_repository_common::table_intact;
352+
ulong Events_common::startup_state= Events_common::EVENTS_OFF;

0 commit comments

Comments
 (0)