sql_trigger.h 10.7 KB
Newer Older
1 2 3
#ifndef SQL_TRIGGER_INCLUDED
#define SQL_TRIGGER_INCLUDED

4
/*
5
   Copyright (c) 2004, 2011, Oracle and/or its affiliates.
6
   Copyright (c) 2017, MariaDB Corporation.
7 8 9

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
10
   the Free Software Foundation; version 2 of the License.
11 12 13 14 15 16 17 18

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
19
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
20

21 22
#include <mysqld_error.h>

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* Forward declarations */

class Item_trigger_field;
class sp_head;
class sp_name;
class Query_tables_list;
struct TABLE_LIST;
class Query_tables_list;

/** Event on which trigger is invoked. */
enum trg_event_type
{
  TRG_EVENT_INSERT= 0,
  TRG_EVENT_UPDATE= 1,
  TRG_EVENT_DELETE= 2,
  TRG_EVENT_MAX
};

41 42 43
static inline uint8 trg2bit(enum trg_event_type trg)
{ return static_cast<uint8>(1 << static_cast<int>(trg)); }

44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include "table.h"                              /* GRANT_INFO */

/*
  We need this two enums here instead of sql_lex.h because
  at least one of them is used by Item_trigger_field interface.

  Time when trigger is invoked (i.e. before or after row actually
  inserted/updated/deleted).
*/
enum trg_action_time_type
{
  TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
};

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
enum trigger_order_type
{
  TRG_ORDER_NONE= 0,
  TRG_ORDER_FOLLOWS= 1,
  TRG_ORDER_PRECEDES= 2
};


struct st_trg_execution_order
{
  /**
    FOLLOWS or PRECEDES as specified in the CREATE TRIGGER statement.
  */
  enum trigger_order_type ordering_clause;

  /**
    Trigger name referenced in the FOLLOWS/PRECEDES clause of the
    CREATE TRIGGER statement.
  */
77
  LEX_CSTRING anchor_trigger_name;
78
};
79

80

81 82 83 84
class Table_triggers_list;

/**
   The trigger object
85
*/
86

87
class Trigger :public Sql_alloc
88
{
89 90 91 92 93 94 95 96 97 98 99
public:
    Trigger(Table_triggers_list *base_arg, sp_head *code):
    base(base_arg), body(code), next(0), trigger_fields(0), action_order(0)
  {
    bzero((char *)&subject_table_grants, sizeof(subject_table_grants));
  }
  ~Trigger();
  Table_triggers_list *base;
  sp_head *body;
  Trigger *next;                                /* Next trigger of same type */

unknown's avatar
unknown committed
100
  /**
101 102 103
    Heads of the lists linking items for all fields used in triggers
    grouped by event and action_time.
  */
104
  Item_trigger_field *trigger_fields;
105 106 107 108
  LEX_CSTRING name;
  LEX_CSTRING on_table_name;                     /* Raw table name */
  LEX_CSTRING definition;
  LEX_CSTRING definer;
109 110

  /* Character sets used */
111 112 113
  LEX_CSTRING client_cs_name;
  LEX_CSTRING connection_cl_name;
  LEX_CSTRING db_cl_name;
114 115

  GRANT_INFO subject_table_grants;
Monty's avatar
Monty committed
116
  sql_mode_t sql_mode;
117 118 119 120 121 122 123
  /* Store create time. Can't be mysql_time_t as this holds also sub seconds */
  ulonglong create_time;
  trg_event_type event;
  trg_action_time_type action_time;
  uint action_order;

  bool is_fields_updated_in_trigger(MY_BITMAP *used_fields);
124
  void get_trigger_info(LEX_CSTRING *stmt, LEX_CSTRING *body,
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
                        LEX_STRING *definer);
  /* Functions executed over each active trigger */
  bool change_on_table_name(void* param_arg);
  bool change_table_name(void* param_arg);
  bool add_to_file_list(void* param_arg);
};

typedef bool (Trigger::*Triggers_processor)(void *arg);

/**
  This class holds all information about triggers of table.
*/

class Table_triggers_list: public Sql_alloc
{
  friend class Trigger;

  /* Points to first trigger for a certain type */
  Trigger *triggers[TRG_EVENT_MAX][TRG_ACTION_MAX];
144 145 146 147 148 149 150
  /**
    Copy of TABLE::Field array which all fields made nullable
    (using extra_null_bitmap, if needed). Used for NEW values in
    BEFORE INSERT/UPDATE triggers.
  */
  Field             **record0_field;
  uchar              *extra_null_bitmap;
unknown's avatar
unknown committed
151
  /**
unknown's avatar
unknown committed
152 153 154
    Copy of TABLE::Field array with field pointers set to TABLE::record[1]
    buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
    trigger and DELETE trigger when it is called for REPLACE).
155
  */
unknown's avatar
unknown committed
156
  Field             **record1_field;
unknown's avatar
unknown committed
157
  /**
unknown's avatar
unknown committed
158 159 160 161 162
    During execution of trigger new_field and old_field should point to the
    array of fields representing new or old version of row correspondingly
    (so it can point to TABLE::field or to Tale_triggers_list::record1_field)
  */
  Field             **new_field;
163
  Field             **old_field;
164

unknown's avatar
unknown committed
165
  /* TABLE instance for which this triggers list object was created */
166
  TABLE *trigger_table;
167

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
  /**
     This flag indicates that one of the triggers was not parsed successfully,
     and as a precaution the object has entered a state where all trigger
     access results in errors until all such triggers are dropped. It is not
     safe to add triggers since we don't know if the broken trigger has the
     same name or event type. Nor is it safe to invoke any trigger for the
     aforementioned reasons. The only safe operations are drop_trigger and
     drop_all_triggers.

     @see Table_triggers_list::set_parse_error
   */
  bool m_has_unparseable_trigger;

  /**
    This error will be displayed when the user tries to manipulate or invoke
    triggers on a table that has broken triggers. It will get set only once
    per statement and thus will contain the first parse error encountered in
    the trigger file.
   */
  char m_parse_error_message[MYSQL_ERRMSG_SIZE];
188
  uint count;                                   /* Number of triggers */
189

190
public:
unknown's avatar
unknown committed
191
  /**
192 193 194
    Field responsible for storing triggers definitions in file.
    It have to be public because we are using it directly from parser.
  */
195
  List<LEX_CSTRING>  definitions_list;
unknown's avatar
unknown committed
196
  /**
197 198 199
    List of sql modes for triggers
  */
  List<ulonglong> definition_modes_list;
200 201
  /** Create times for triggers */
  List<ulonglong> create_times;
202

203
  List<LEX_CSTRING>  definers_list;
204

unknown's avatar
unknown committed
205 206
  /* Character set context, used for parsing and executing triggers. */

207 208 209
  List<LEX_CSTRING> client_cs_names;
  List<LEX_CSTRING> connection_cl_names;
  List<LEX_CSTRING> db_cl_names;
unknown's avatar
unknown committed
210 211 212

  /* End of character ser context. */

213
  Table_triggers_list(TABLE *table_arg)
214
    :record0_field(0), extra_null_bitmap(0), record1_field(0),
215
    trigger_table(table_arg),
216
    m_has_unparseable_trigger(false), count(0)
217
  {
218
    bzero((char *) triggers, sizeof(triggers));
219 220 221
  }
  ~Table_triggers_list();

222 223
  bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
  bool drop_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
224
  bool process_triggers(THD *thd, trg_event_type event,
unknown's avatar
unknown committed
225
                        trg_action_time_type time_type,
226
                        bool old_row_is_record1);
227 228
  void empty_lists();
  bool create_lists_needed_for_files(MEM_ROOT *root);
229
  bool save_trigger_file(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name);
230

231
  static bool check_n_load(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name,
232
                           TABLE *table, bool names_only);
233 234 235 236 237 238 239
  static bool drop_all_triggers(THD *thd, const LEX_CSTRING *db,
                                const LEX_CSTRING *table_name);
  static bool change_table_name(THD *thd, const LEX_CSTRING *db,
                                const LEX_CSTRING *old_alias,
                                const LEX_CSTRING *old_table,
                                const LEX_CSTRING *new_db,
                                const LEX_CSTRING *new_table);
240 241 242
  void add_trigger(trg_event_type event_type, 
                   trg_action_time_type action_time,
                   trigger_order_type ordering_clause,
243
                   LEX_CSTRING *anchor_trigger_name,
244 245 246 247 248 249 250 251 252 253 254 255 256
                   Trigger *trigger);
  Trigger *get_trigger(trg_event_type event_type, 
                       trg_action_time_type action_time)
  {
    return triggers[event_type][action_time];
  }
  /* Simpler version of the above, to avoid casts in the code */
  Trigger *get_trigger(uint event_type, uint action_time)
  {
    return get_trigger((trg_event_type) event_type,
                       (trg_action_time_type) action_time);
  }

257 258 259
  bool has_triggers(trg_event_type event_type, 
                    trg_action_time_type action_time)
  {
260
    return get_trigger(event_type,action_time) != 0;
261
  }
262 263
  bool has_delete_triggers()
  {
264 265
    return (has_triggers(TRG_EVENT_DELETE,TRG_ACTION_BEFORE) ||
            has_triggers(TRG_EVENT_DELETE,TRG_ACTION_AFTER));
266 267
  }

268
  void mark_fields_used(trg_event_type event);
269

270 271
  void set_parse_error_message(char *error_message);

272
  friend class Item_trigger_field;
Konstantin Osipov's avatar
Konstantin Osipov committed
273 274 275 276

  bool add_tables_and_routines_for_triggers(THD *thd,
                                            Query_tables_list *prelocking_ctx,
                                            TABLE_LIST *table_list);
277

278 279 280
  Field **nullable_fields() { return record0_field; }
  void reset_extra_null_bitmap()
  {
281 282
    size_t null_bytes= (trigger_table->s->stored_fields -
                        trigger_table->s->null_fields + 7)/8;
283 284 285
    bzero(extra_null_bitmap, null_bytes);
  }

286
  Trigger *find_trigger(const LEX_CSTRING *name, bool remove_from_list);
287 288 289

  Trigger* for_all_triggers(Triggers_processor func, void *arg);

290
private:
291
  bool prepare_record_accessors(TABLE *table);
292 293 294
  Trigger *change_table_name_in_trignames(const LEX_CSTRING *old_db_name,
                                          const LEX_CSTRING *new_db_name,
                                          const LEX_CSTRING *new_table_name,
295
                                          Trigger *trigger);
296
  bool change_table_name_in_triggers(THD *thd,
297 298 299 300
                                     const LEX_CSTRING *old_db_name,
                                     const LEX_CSTRING *new_db_name,
                                     const LEX_CSTRING *old_table_name,
                                     const LEX_CSTRING *new_table_name);
301 302 303 304 305 306 307 308 309 310

  bool check_for_broken_triggers() 
  {
    if (m_has_unparseable_trigger)
    {
      my_message(ER_PARSE_ERROR, m_parse_error_message, MYF(0));
      return true;
    }
    return false;
  }
311
};
312

313
bool add_table_for_trigger(THD *thd,
unknown's avatar
unknown committed
314
                           const sp_name *trg_name,
315 316 317 318 319
                           bool continue_if_not_exist,
                           TABLE_LIST **table);

void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path);

320
bool check_trn_exists(const LEX_CSTRING *trn_path);
321 322 323

bool load_table_name_for_trigger(THD *thd,
                                 const sp_name *trg_name,
324 325
                                 const LEX_CSTRING *trn_path,
                                 LEX_CSTRING *tbl_name);
326 327 328 329
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);

extern const char * const TRG_EXT;
extern const char * const TRN_EXT;
330

331
#endif /* SQL_TRIGGER_INCLUDED */