1 /*
2 Copyright (c) 2014, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23
24 #include "my_global.h"
25 #include "trigger_loader.h"
26 #include "sql_class.h"
27 #include "sp_head.h" // sp_name
28 #include "sql_base.h" // is_equal(LEX_STRING, LEX_STRING)
29 #include "sql_table.h" // build_table_filename()
30 #include <mysys_err.h> // EE_OUTOFMEMORY
31 #include "parse_file.h" // File_option
32 #include "trigger.h"
33
34 #include "pfs_file_provider.h"
35 #include "mysql/psi/mysql_file.h"
36
37 #include "mysql/psi/mysql_sp.h"
38
39 ///////////////////////////////////////////////////////////////////////////
40
41 const char * const TRN_EXT= ".TRN";
42 const char * const TRG_EXT= ".TRG";
43
44 ///////////////////////////////////////////////////////////////////////////
45
46 /**
47 This must be kept up to date whenever a new option is added to the list
48 above, as it specifies the number of required parameters of the trigger in
49 .trg file.
50 */
51
52 static const int TRG_NUM_REQUIRED_PARAMETERS= 8;
53
54 const LEX_STRING trg_file_type= { C_STRING_WITH_LEN("TRIGGERS") };
55
56 const LEX_STRING trn_file_type= { C_STRING_WITH_LEN("TRIGGERNAME") };
57
58 ///////////////////////////////////////////////////////////////////////////
59 ///////////////////////////////////////////////////////////////////////////
60
61 /*
62 Structure representing contents of .TRN file which are used to support
63 database wide trigger namespace.
64 */
65
66 struct Trn_file_data
67 {
68 LEX_STRING trigger_table;
69 };
70
71 ///////////////////////////////////////////////////////////////////////////
72
73 static File_option trn_file_parameters[]=
74 {
75 {
76 { C_STRING_WITH_LEN("trigger_table")},
77 offsetof(struct Trn_file_data, trigger_table),
78 FILE_OPTIONS_ESTRING
79 },
80 { { 0, 0 }, 0, FILE_OPTIONS_STRING }
81 };
82
83 ///////////////////////////////////////////////////////////////////////////
84 ///////////////////////////////////////////////////////////////////////////
85
86 /**
87 Structure representing contents of .TRG file.
88 */
89
90 struct Trg_file_data
91 {
92 /// List of CREATE TRIGGER statements.
93 List<LEX_STRING> definitions;
94
95 /// List of 'sql mode' values.
96 List<ulonglong> sql_modes;
97
98 /// List of 'definer' values.
99 List<LEX_STRING> definers_list;
100
101 /// List of client character set names.
102 List<LEX_STRING> client_cs_names;
103
104 /// List of connection collation names.
105 List<LEX_STRING> connection_cl_names;
106
107 /// List of database collation names.
108 List<LEX_STRING> db_cl_names;
109
110 /// List of trigger creation time stamps
111 List<longlong> created_timestamps;
112
append_triggerTrg_file_data113 bool append_trigger(Trigger *t, MEM_ROOT *m)
114 {
115 return
116 definitions.push_back(t->get_definition_ptr(), m) ||
117 sql_modes.push_back(t->get_sql_mode_ptr(), m) ||
118 definers_list.push_back(t->get_definer_ptr(), m) ||
119 client_cs_names.push_back(t->get_client_cs_name_ptr(), m) ||
120 connection_cl_names.push_back(t->get_connection_cl_name_ptr(), m) ||
121 db_cl_names.push_back(t->get_db_cl_name_ptr(), m) ||
122 created_timestamps.push_back(t->get_created_timestamp_ptr(), m);
123 }
124 };
125
126 ///////////////////////////////////////////////////////////////////////////
127
128 /**
129 Table of .TRG file field descriptors.
130 */
131
132 static File_option trg_file_parameters[]=
133 {
134 {
135 { C_STRING_WITH_LEN("triggers") },
136 my_offsetof(struct Trg_file_data, definitions),
137 FILE_OPTIONS_STRLIST
138 },
139 {
140 { C_STRING_WITH_LEN("sql_modes") },
141 my_offsetof(struct Trg_file_data, sql_modes),
142 FILE_OPTIONS_ULLLIST
143 },
144 {
145 { C_STRING_WITH_LEN("definers") },
146 my_offsetof(struct Trg_file_data, definers_list),
147 FILE_OPTIONS_STRLIST
148 },
149 {
150 { C_STRING_WITH_LEN("client_cs_names") },
151 my_offsetof(struct Trg_file_data, client_cs_names),
152 FILE_OPTIONS_STRLIST
153 },
154 {
155 { C_STRING_WITH_LEN("connection_cl_names") },
156 my_offsetof(struct Trg_file_data, connection_cl_names),
157 FILE_OPTIONS_STRLIST
158 },
159 {
160 { C_STRING_WITH_LEN("db_cl_names") },
161 my_offsetof(struct Trg_file_data, db_cl_names),
162 FILE_OPTIONS_STRLIST
163 },
164 {
165 { C_STRING_WITH_LEN("created") },
166 my_offsetof(struct Trg_file_data, created_timestamps),
167 FILE_OPTIONS_ULLLIST
168 },
169 { { 0, 0 }, 0, FILE_OPTIONS_STRING }
170 };
171
172 ///////////////////////////////////////////////////////////////////////////
173
174 static File_option sql_modes_parameters=
175 {
176 { C_STRING_WITH_LEN("sql_modes") },
177 my_offsetof(struct Trg_file_data, sql_modes),
178 FILE_OPTIONS_ULLLIST
179 };
180
181 ///////////////////////////////////////////////////////////////////////////
182 ///////////////////////////////////////////////////////////////////////////
183
build_trn_path(char * trn_file_name_buffer,int trn_file_name_buffer_size,const char * db_name,const char * trigger_name)184 LEX_STRING Trigger_loader::build_trn_path(char *trn_file_name_buffer,
185 int trn_file_name_buffer_size,
186 const char *db_name,
187 const char *trigger_name)
188 {
189 bool was_truncated= false;
190 LEX_STRING trn_file_name;
191
192 trn_file_name.str= trn_file_name_buffer;
193 trn_file_name.length= build_table_filename(trn_file_name_buffer,
194 trn_file_name_buffer_size - 1,
195 db_name, trigger_name,
196 TRN_EXT, 0, &was_truncated);
197
198 if (!was_truncated)
199 return trn_file_name;
200
201 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0),
202 sizeof (trn_file_name_buffer) - 1,
203 trn_file_name_buffer);
204
205 trn_file_name= NULL_STR;
206
207 return trn_file_name;
208 }
209
210 /**
211 This method saves .TRG file for the table specified by arguments.
212
213 @param db_name Name of database for subject table
214 @param table_name Name of subject table
215
216 @return Operation status.
217 @retval false Success
218 @retval true Failure
219 */
220
save_trg_file(const char * db_name,const char * table_name,const Trg_file_data * trg)221 static bool save_trg_file(const char *db_name,
222 const char *table_name,
223 const Trg_file_data *trg)
224 {
225 char trg_file_name_buffer[FN_REFLEN];
226 LEX_STRING trg_file_name;
227 bool was_truncated= false;
228
229 trg_file_name.length= build_table_filename(trg_file_name_buffer,
230 FN_REFLEN - 1,
231 db_name, table_name,
232 TRG_EXT, 0, &was_truncated);
233
234 if (was_truncated)
235 {
236 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0),
237 sizeof (trg_file_name_buffer) - 1,
238 trg_file_name_buffer);
239 return true;
240 }
241
242 trg_file_name.str= trg_file_name_buffer;
243 return sql_create_definition_file(NULL, &trg_file_name, &trg_file_type,
244 (uchar*) trg, trg_file_parameters);
245 }
246
247
248 /**
249 Deletes the .TRN file for a trigger.
250
251 @param [in] db_name trigger's database name
252 @param [in] trigger_name trigger's name
253
254 @return Operation status.
255 @retval true Failure
256 @retval false Success
257 */
258
rm_trn_file(const char * db_name,const char * trigger_name)259 static bool rm_trn_file(const char *db_name, const char *trigger_name)
260 {
261 char path[FN_REFLEN];
262
263 build_table_filename(path, FN_REFLEN - 1, db_name, trigger_name, TRN_EXT, 0);
264 return mysql_file_delete(key_file_trn, path, MYF(MY_WME));
265 }
266
267
268 /**
269 Deletes the .TRG file for a table.
270
271 @param db_name table's database name
272 @param table_name table's name
273
274 @return Operation status.
275 @retval true Failure
276 @retval false Success
277 */
278
rm_trg_file(const char * db_name,const char * table_name)279 static bool rm_trg_file(const char *db_name, const char *table_name)
280 {
281 char path[FN_REFLEN];
282
283 build_table_filename(path, FN_REFLEN - 1, db_name, table_name, TRG_EXT, 0);
284 return mysql_file_delete(key_file_trg, path, MYF(MY_WME));
285 }
286
fill_trg_data(Trg_file_data * trg,MEM_ROOT * mem_root,List<Trigger> * triggers)287 static bool fill_trg_data(Trg_file_data *trg,
288 MEM_ROOT *mem_root,
289 List<Trigger> *triggers)
290 {
291 List_iterator<Trigger> it(*triggers);
292 Trigger *t;
293
294 while ((t= it++))
295 {
296 if (trg->append_trigger(t, mem_root))
297 return true;
298 }
299
300 return false;
301 }
302
303 /**
304 Change the subject table in the given list of triggers.
305
306 @param db_name Old database of subject table
307 @param new_db_name New database of subject table
308 @param new_table_name New subject table's name
309 @param stopper Pointer to a trigger_name for
310 which we should stop updating.
311
312 @retval NULL Success
313 @retval not-NULL Failure, pointer to Table_trigger_dispatcher::names_list
314 element for which update failed.
315 */
316
change_table_name_in_trn_files(List<Trigger> * triggers,const char * db_name,const char * new_db_name,const LEX_STRING * new_table_name,const Trigger * stopper)317 static Trigger *change_table_name_in_trn_files(
318 List<Trigger> *triggers,
319 const char *db_name,
320 const char *new_db_name,
321 const LEX_STRING *new_table_name,
322 const Trigger *stopper)
323 {
324 List_iterator_fast<Trigger> it(*triggers);
325 Trigger *t;
326
327 while ((t= it++))
328 {
329 if (t == stopper)
330 break;
331
332 // Get TRN file name.
333
334 char trn_file_name_buffer[FN_REFLEN];
335
336 LEX_STRING trn_file_name=
337 Trigger_loader::build_trn_path(trn_file_name_buffer, FN_REFLEN,
338 new_db_name, t->get_trigger_name().str);
339
340 if (!trn_file_name.str)
341 return NULL; // FIXME: OOM
342
343 // Prepare TRN data.
344
345 Trn_file_data trn;
346 trn.trigger_table= *new_table_name;
347
348 // Create new TRN file.
349
350 if (sql_create_definition_file(NULL, &trn_file_name, &trn_file_type,
351 (uchar *) &trn, trn_file_parameters))
352 {
353 return t;
354 }
355
356 // Remove stale .TRN file in case of database upgrade.
357
358 if (db_name)
359 {
360 if (rm_trn_file(db_name, t->get_trigger_name().str))
361 {
362 rm_trn_file(new_db_name, t->get_trigger_name().str);
363 return t;
364 }
365 }
366 }
367
368 return NULL;
369 }
370
371 ///////////////////////////////////////////////////////////////////////////
372 ///////////////////////////////////////////////////////////////////////////
373
374 class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
375 {
376 private:
377 char *path;
378 public:
Handle_old_incorrect_sql_modes_hook(char * file_path)379 Handle_old_incorrect_sql_modes_hook(char *file_path)
380 :path(file_path)
381 {};
382 virtual bool process_unknown_string(const char *&unknown_key, uchar *base,
383 MEM_ROOT *mem_root, const char *end);
384 };
385
386 ///////////////////////////////////////////////////////////////////////////
387
388 class Handle_old_incorrect_trigger_table_hook: public Unknown_key_hook
389 {
390 public:
Handle_old_incorrect_trigger_table_hook(char * file_path,LEX_STRING * trigger_table_arg)391 Handle_old_incorrect_trigger_table_hook(char *file_path,
392 LEX_STRING *trigger_table_arg)
393 :path(file_path), trigger_table_value(trigger_table_arg)
394 {};
395 virtual bool process_unknown_string(const char *&unknown_key, uchar *base,
396 MEM_ROOT *mem_root, const char *end);
397 private:
398 char *path;
399 LEX_STRING *trigger_table_value;
400 };
401
402 ///////////////////////////////////////////////////////////////////////////
403
404 /**
405 Trigger BUG#14090 compatibility hook.
406
407 @param[in,out] unknown_key reference on the line with unknown
408 parameter and the parsing point
409 @param[in] base base address for parameter writing
410 (structure like TABLE)
411 @param[in] mem_root MEM_ROOT for parameters allocation
412 @param[in] end the end of the configuration
413
414 @note
415 NOTE: this hook process back compatibility for incorrectly written
416 sql_modes parameter (see BUG#14090).
417
418 @retval
419 false OK
420 @retval
421 true Error
422 */
423
424 #define INVALID_SQL_MODES_LENGTH 13
425
process_unknown_string(const char * & unknown_key,uchar * base,MEM_ROOT * mem_root,const char * end)426 bool Handle_old_incorrect_sql_modes_hook::process_unknown_string(
427 const char *&unknown_key,
428 uchar *base,
429 MEM_ROOT *mem_root,
430 const char *end)
431 {
432 DBUG_ENTER("Handle_old_incorrect_sql_modes_hook::process_unknown_string");
433 DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
434
435 if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end &&
436 unknown_key[INVALID_SQL_MODES_LENGTH] == '=' &&
437 !memcmp(unknown_key, STRING_WITH_LEN("sql_modes")))
438 {
439 const char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1;
440
441 DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected"));
442 push_warning_printf(current_thd,
443 Sql_condition::SL_NOTE,
444 ER_OLD_FILE_FORMAT,
445 ER(ER_OLD_FILE_FORMAT),
446 path, "TRIGGER");
447 if (get_file_options_ulllist(ptr, end, unknown_key, base,
448 &sql_modes_parameters, mem_root))
449 {
450 DBUG_RETURN(true);
451 }
452 /*
453 Set parsing pointer to the last symbol of string (\n)
454 1) to avoid problem with \0 in the junk after sql_modes
455 2) to speed up skipping this line by parser.
456 */
457 unknown_key= ptr-1;
458 }
459 DBUG_RETURN(false);
460 }
461
462 ///////////////////////////////////////////////////////////////////////////
463
464 #define INVALID_TRIGGER_TABLE_LENGTH 15
465
466 /**
467 Trigger BUG#15921 compatibility hook. For details see
468 Handle_old_incorrect_sql_modes_hook::process_unknown_string().
469 */
470
process_unknown_string(const char * & unknown_key,uchar * base,MEM_ROOT * mem_root,const char * end)471 bool Handle_old_incorrect_trigger_table_hook::process_unknown_string(
472 const char *&unknown_key,
473 uchar *base,
474 MEM_ROOT *mem_root,
475 const char *end)
476 {
477 DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string");
478 DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
479
480 if (unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1 < end &&
481 unknown_key[INVALID_TRIGGER_TABLE_LENGTH] == '=' &&
482 !memcmp(unknown_key, STRING_WITH_LEN("trigger_table")))
483 {
484 const char *ptr= unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1;
485
486 DBUG_PRINT("info", ("trigger_table affected by BUG#15921 detected"));
487 push_warning_printf(current_thd,
488 Sql_condition::SL_NOTE,
489 ER_OLD_FILE_FORMAT,
490 ER(ER_OLD_FILE_FORMAT),
491 path, "TRIGGER");
492
493 if (!(ptr= parse_escaped_string(ptr, end, mem_root, trigger_table_value)))
494 {
495 my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), "trigger_table",
496 unknown_key);
497 DBUG_RETURN(true);
498 }
499
500 /* Set parsing pointer to the last symbol of string (\n). */
501 unknown_key= ptr-1;
502 }
503 DBUG_RETURN(false);
504 }
505
506 ///////////////////////////////////////////////////////////////////////////
507 ///////////////////////////////////////////////////////////////////////////
508
509 /*
510 Module private variables to be used in Trigger_loader::load_triggers().
511 */
512
513 static LEX_STRING default_definer= EMPTY_STR;
514
515 static LEX_STRING default_client_cs_name= NULL_STR;
516 static LEX_STRING default_connection_cl_name= NULL_STR;
517 static LEX_STRING default_db_cl_name= NULL_STR;
518
519 ///////////////////////////////////////////////////////////////////////////
520 ///////////////////////////////////////////////////////////////////////////
521
522 /**
523 Check if TRN-file exists.
524
525 @param trn_path path to TRN-file
526
527 @return true if TRN-file does not exists, false otherwise.
528 */
529
check_trn_exists(const LEX_STRING & trn_path)530 bool Trigger_loader::check_trn_exists(const LEX_STRING &trn_path)
531 {
532 return access(trn_path.str, F_OK) != 0;
533 }
534
535 ///////////////////////////////////////////////////////////////////////////
536
537 /**
538 Check if the TRG-file for the given table exists.
539
540 @param db_name name of schema
541 @param table_name name of trigger
542
543 @return true if TRG-file exists, false otherwise.
544 */
trg_file_exists(const char * db_name,const char * table_name)545 bool Trigger_loader::trg_file_exists(const char *db_name,
546 const char *table_name)
547 {
548 char path[FN_REFLEN];
549 build_table_filename(path, FN_REFLEN - 1, db_name, table_name, TRG_EXT, 0);
550
551 if (access(path, F_OK))
552 {
553 if (errno == ENOENT)
554 return false;
555 }
556
557 return true;
558 }
559
560
561 /**
562 Load table triggers from the data dictionary.
563
564 @param [in] thd thread handle
565 @param [in] db_name name of schema
566 @param [in] table_name subject table name
567 @param [out] triggers pointer to the list where new Trigger
568 objects will be inserted
569
570 @return Operation status
571 @retval true Failure
572 @retval false Success
573 */
574
load_triggers(THD * thd,MEM_ROOT * mem_root,const char * db_name,const char * table_name,List<Trigger> * triggers)575 bool Trigger_loader::load_triggers(THD *thd,
576 MEM_ROOT *mem_root,
577 const char *db_name,
578 const char *table_name,
579 List<Trigger> *triggers)
580 {
581 DBUG_ENTER("Trigger_loader::load_triggers");
582
583 // Construct TRG-file name.
584
585 char trg_file_path_buffer[FN_REFLEN];
586 LEX_STRING trg_file_path;
587
588 trg_file_path.length= build_table_filename(trg_file_path_buffer,
589 FN_REFLEN - 1,
590 db_name, table_name, TRG_EXT, 0);
591 trg_file_path.str= trg_file_path_buffer;
592
593 // The TRG-file exists so we got to load triggers.
594
595 File_parser *parser=
596 sql_parse_prepare(&trg_file_path, mem_root, true);
597
598 if (!parser)
599 DBUG_RETURN(true);
600
601 if (!is_equal(&trg_file_type, parser->type()))
602 {
603 my_error(ER_WRONG_OBJECT, MYF(0), table_name, TRG_EXT + 1, "TRIGGER");
604 DBUG_RETURN(true);
605 }
606
607 Handle_old_incorrect_sql_modes_hook sql_modes_hook(trg_file_path.str);
608
609 Trg_file_data trg;
610
611 if (parser->parse((uchar*) &trg,
612 mem_root,
613 trg_file_parameters,
614 TRG_NUM_REQUIRED_PARAMETERS,
615 &sql_modes_hook))
616 DBUG_RETURN(true);
617
618 if (trg.definitions.is_empty())
619 {
620 assert(trg.sql_modes.is_empty());
621 assert(trg.definers_list.is_empty());
622 assert(trg.client_cs_names.is_empty());
623 assert(trg.connection_cl_names.is_empty());
624 assert(trg.db_cl_names.is_empty());
625 DBUG_RETURN(false);
626 }
627
628 // Make sure character set properties are filled.
629
630 if (trg.client_cs_names.is_empty() ||
631 trg.connection_cl_names.is_empty() ||
632 trg.db_cl_names.is_empty())
633 {
634 if (!trg.client_cs_names.is_empty() ||
635 !trg.connection_cl_names.is_empty() ||
636 !trg.db_cl_names.is_empty())
637 {
638 my_error(ER_TRG_CORRUPTED_FILE, MYF(0),
639 db_name,
640 table_name);
641
642 DBUG_RETURN(true);
643 }
644
645 push_warning_printf(thd, Sql_condition::SL_WARNING,
646 ER_TRG_NO_CREATION_CTX,
647 ER(ER_TRG_NO_CREATION_CTX),
648 db_name,
649 table_name);
650
651
652 /*
653 Backward compatibility: assume that the query is in the current
654 character set.
655 */
656
657 lex_string_set(&default_client_cs_name,
658 thd->variables.character_set_client->csname);
659
660 lex_string_set(&default_connection_cl_name,
661 thd->variables.collation_connection->name);
662
663 lex_string_set(&default_db_cl_name,
664 thd->variables.collation_database->name);
665 }
666
667 LEX_CSTRING db_name_str= {db_name, strlen(db_name)};
668
669 LEX_CSTRING table_name_str= {table_name, strlen(table_name)};
670
671 List_iterator_fast<LEX_STRING> it_definition(trg.definitions);
672 List_iterator_fast<sql_mode_t> it_sql_mode(trg.sql_modes);
673 List_iterator_fast<LEX_STRING> it_definer(trg.definers_list);
674 List_iterator_fast<LEX_STRING> it_client_cs_name(trg.client_cs_names);
675 List_iterator_fast<LEX_STRING> it_connect_cl_name(trg.connection_cl_names);
676 List_iterator_fast<LEX_STRING> it_db_cl_name(trg.db_cl_names);
677 List_iterator_fast<longlong> it_created_timestamps(trg.created_timestamps);
678
679 while (true)
680 {
681 const LEX_STRING *definition= it_definition++;
682
683 if (!definition)
684 break;
685
686 const sql_mode_t *sql_mode= it_sql_mode++;
687 const LEX_STRING *definer= it_definer++;
688 const LEX_STRING *client_cs_name= it_client_cs_name++;
689 const LEX_STRING *connection_cl_name= it_connect_cl_name++;
690 const LEX_STRING *db_cl_name= it_db_cl_name++;
691 const longlong *created_timestamp= it_created_timestamps++;
692
693 // Backward compatibility: use default settings if attributes are missing.
694
695 if (!sql_mode)
696 sql_mode= &global_system_variables.sql_mode;
697
698 if (!definer)
699 definer= &default_definer;
700
701 if (!client_cs_name)
702 client_cs_name= &default_client_cs_name;
703
704 if (!connection_cl_name)
705 connection_cl_name= &default_connection_cl_name;
706
707 if (!db_cl_name)
708 db_cl_name= &default_db_cl_name;
709
710 // Create a new trigger instance.
711
712 Trigger *t= Trigger::create_from_dd(mem_root,
713 db_name_str,
714 table_name_str,
715 *definition,
716 *sql_mode,
717 *definer,
718 *client_cs_name,
719 *connection_cl_name,
720 *db_cl_name,
721 created_timestamp);
722
723 // NOTE: new trigger object is not fully initialized here.
724
725 if (triggers->push_back(t, mem_root))
726 {
727 delete t;
728 DBUG_RETURN(true);
729 }
730 }
731
732 DBUG_RETURN(false);
733 }
734
735 ///////////////////////////////////////////////////////////////////////////
736
737 /**
738 Store a table trigger into the data dictionary.
739
740 @param [in] tables pointer to trigger's table
741 @param [in] new_trigger trigger to save
742 @param [in] triggers pointer to the list where new trigger object has to
743 be added
744
745 @return Operation status
746 @retval true Failure
747 @retval false Success
748 */
749
store_trigger(const LEX_STRING & db_name,const LEX_STRING & table_name,MEM_ROOT * mem_root,Trigger * new_trigger,List<Trigger> * triggers)750 bool Trigger_loader::store_trigger(const LEX_STRING &db_name,
751 const LEX_STRING &table_name,
752 MEM_ROOT *mem_root,
753 Trigger *new_trigger,
754 List<Trigger> *triggers)
755 {
756 // Fill TRN-data structure.
757
758 Trn_file_data trn;
759
760 trn.trigger_table= table_name;
761
762 // Fill TRG-data structure.
763
764 Trg_file_data trg;
765
766 if (fill_trg_data(&trg, mem_root, triggers))
767 return true;
768
769 // Get TRN file name.
770
771 char trn_file_name_buffer[FN_REFLEN];
772
773 LEX_STRING trn_file_name=
774 Trigger_loader::build_trn_path(trn_file_name_buffer, FN_REFLEN,
775 db_name.str,
776 new_trigger->get_trigger_name().str);
777
778 if (!trn_file_name.str)
779 return true; // my_error() has already been called.
780
781 // Save TRN file.
782
783 if (sql_create_definition_file(NULL, &trn_file_name, &trn_file_type,
784 (uchar *) &trn, trn_file_parameters))
785 {
786 return true; // my_error() has already been called.
787 }
788
789 // Save TRG file.
790
791 if (save_trg_file(db_name.str, table_name.str, &trg))
792 {
793 mysql_file_delete(key_file_trn, trn_file_name.str, MYF(MY_WME));
794 return true;
795 }
796
797 return false;
798 }
799
800 ///////////////////////////////////////////////////////////////////////////
801
802 /**
803 Drop trigger in the data dictionary.
804
805 @param [in] tables pointer to trigger's table
806 @param [in] trigger_name name of the trigger to drop
807 @param [in] triggers list of all table triggers
808 @param [out] trigger_found flag to store a result whether
809 the named trigger was found
810
811 @return Operation status.
812 @retval true Failure
813 @retval false Success
814 */
815
drop_trigger(const LEX_STRING & db_name,const LEX_STRING & table_name,const LEX_STRING & trigger_name,MEM_ROOT * mem_root,List<Trigger> * triggers,bool * trigger_found)816 bool Trigger_loader::drop_trigger(const LEX_STRING &db_name,
817 const LEX_STRING &table_name,
818 const LEX_STRING &trigger_name,
819 MEM_ROOT *mem_root,
820 List<Trigger> *triggers,
821 bool *trigger_found)
822 {
823 // Create TRG-data with all table triggers but the trigger to drop.
824
825 Trg_file_data trg;
826 *trigger_found= false;
827
828 {
829 List_iterator<Trigger> it(*triggers);
830 Trigger *t;
831
832 while ((t= it++))
833 {
834 if (my_strcasecmp(table_alias_charset,
835 t->get_trigger_name().str,
836 trigger_name.str) == 0)
837 {
838 delete t;
839 it.remove(); // Remove trigger from the list.
840 *trigger_found= true;
841 continue;
842 }
843
844 if (trg.append_trigger(t, mem_root))
845 return true;
846 }
847 }
848
849 // Remove TRN file.
850
851 if (rm_trn_file(db_name.str, trigger_name.str))
852 return true;
853
854 // If we've just dropped the last trigger, remove TRG file. Otherwise, save
855 // new TRG file.
856
857 return triggers->is_empty() ?
858 rm_trg_file(db_name.str, table_name.str) :
859 save_trg_file(db_name.str, table_name.str, &trg);
860 }
861
862 ///////////////////////////////////////////////////////////////////////////
863
864 /**
865 Load trigger table name from TRN-file.
866
867 @param [in] thd thread handle
868 @param [in] trigger_name name of trigger
869 @param [in] trn_path path to the corresponding TRN-file
870 @param [out] tbl_name variable to store retrieved table name
871
872 @return Operation status
873 @retval true Failure.
874 @retval false Success.
875 */
876
load_trn_file(THD * thd,const LEX_STRING & trigger_name,const LEX_STRING & trn_path,LEX_STRING * tbl_name)877 bool Trigger_loader::load_trn_file(THD *thd,
878 const LEX_STRING &trigger_name,
879 const LEX_STRING &trn_path,
880 LEX_STRING *tbl_name)
881 {
882 DBUG_ENTER("Trigger_loader::get_table_name_for_trigger()");
883
884 /* Prepare the File_parser to parse the TRN-file. */
885
886 File_parser *parser= sql_parse_prepare(&trn_path, thd->mem_root, true);
887
888 if (!parser)
889 DBUG_RETURN(true);
890
891 if (!is_equal(&trn_file_type, parser->type()))
892 {
893 my_error(ER_WRONG_OBJECT, MYF(0),
894 trigger_name.str,
895 TRN_EXT + 1,
896 "TRIGGERNAME");
897
898 DBUG_RETURN(true);
899 }
900
901 /* Parse the TRN-file. */
902
903 Trn_file_data trn;
904
905 Handle_old_incorrect_trigger_table_hook trigger_table_hook(
906 trn_path.str,
907 &trn.trigger_table);
908
909
910 if (parser->parse((uchar *) &trn, thd->mem_root,
911 trn_file_parameters, 1,
912 &trigger_table_hook))
913 DBUG_RETURN(true);
914
915 /* Copy trigger table name. */
916
917 *tbl_name= trn.trigger_table;
918
919 /* That's all. */
920
921 DBUG_RETURN(false);
922 }
923
924 ///////////////////////////////////////////////////////////////////////////
925
926 /**
927 Drop all triggers for the given table.
928 */
929
drop_all_triggers(const char * db_name,const char * table_name,List<Trigger> * triggers)930 bool Trigger_loader::drop_all_triggers(const char *db_name,
931 const char *table_name,
932 List<Trigger> *triggers)
933 {
934 bool rc= false;
935
936 List_iterator_fast<Trigger> it(*triggers);
937 Trigger *t;
938
939 while ((t= it++))
940 {
941 LEX_STRING trigger_name= t->get_trigger_name();
942 if (rm_trn_file(db_name, trigger_name.str))
943 {
944 rc= true;
945 continue;
946 }
947 #ifdef HAVE_PSI_SP_INTERFACE
948 LEX_CSTRING db_name= t->get_db_name();
949 /* Drop statistics for this stored program from performance schema. */
950 MYSQL_DROP_SP(SP_TYPE_TRIGGER,
951 db_name.str, db_name.length,
952 trigger_name.str, trigger_name.length);
953 #endif
954 }
955
956 return rm_trg_file(db_name, table_name) || rc;
957 }
958
959 ///////////////////////////////////////////////////////////////////////////
960
rename_subject_table(MEM_ROOT * mem_root,List<Trigger> * triggers,const char * db_name,LEX_STRING * table_name,const char * new_db_name,LEX_STRING * new_table_name,bool upgrading50to51)961 bool Trigger_loader::rename_subject_table(MEM_ROOT *mem_root,
962 List<Trigger> *triggers,
963 const char *db_name,
964 LEX_STRING *table_name,
965 const char *new_db_name,
966 LEX_STRING *new_table_name,
967 bool upgrading50to51)
968 {
969 // Prepare TRG-data. Do it here so that OOM-error will not cause data
970 // inconsistency.
971
972 Trg_file_data trg;
973
974 if (fill_trg_data(&trg, mem_root, triggers))
975 return true;
976
977 // Change the subject table name in TRN files for all triggers.
978
979 Trigger *err_trigger=
980 change_table_name_in_trn_files(triggers,
981 upgrading50to51 ? db_name : NULL,
982 new_db_name, new_table_name,
983 NULL);
984
985 if (err_trigger)
986 {
987 /*
988 If we were unable to update one of .TRN files properly we will
989 revert all changes that we have done and report about error.
990 We assume that we will be able to undo our changes without errors
991 (we can't do much if there will be an error anyway).
992 */
993 change_table_name_in_trn_files(
994 triggers,
995 upgrading50to51 ? new_db_name : NULL,
996 db_name, table_name,
997 err_trigger);
998 return true;
999 }
1000
1001 // Save new TRG file.
1002
1003 if (save_trg_file(new_db_name, new_table_name->str, &trg))
1004 return true;
1005
1006 // Remove old TRG file.
1007
1008 if (rm_trg_file(db_name, table_name->str))
1009 {
1010 rm_trg_file(new_db_name, new_table_name->str);
1011 return true;
1012 }
1013
1014 return false;
1015 }
1016