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