/* Copyright (C) 2004-2005 MySQL AB

   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */


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

  QQ: Will it be merged into TABLE in future ?
*/

class Table_triggers_list: public Sql_alloc
{
  /* Triggers as SPs grouped by event, action_time */
  sp_head           *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
  /*
    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).
  */
  Field             **record1_field;
  /*
    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;
  Field             **old_field;
  /* TABLE instance for which this triggers list object was created */
  TABLE *table;
  /*
    Names of triggers.
    Should correspond to order of triggers on definitions_list,
    used in CREATE/DROP TRIGGER for looking up trigger by name.
  */
  List<LEX_STRING>  names_list;
  /*
    Key representing triggers for this table in set of all stored
    routines used by statement.
    TODO: We won't need this member once triggers namespace will be
    database-wide instead of table-wide because then we will be able
    to use key based on sp_name as for other stored routines.
  */
  LEX_STRING        sroutines_key;

  /*
    is_special_var_used specifies whether trigger body contains special
    variables (NEW/OLD).
  */
  bool m_spec_var_used[TRG_EVENT_MAX][TRG_ACTION_MAX];

public:
  /*
    Field responsible for storing triggers definitions in file.
    It have to be public because we are using it directly from parser.
  */
  List<LEX_STRING>  definitions_list;
  /*
    List of sql modes for triggers
  */
  List<ulonglong> definition_modes_list;

  List<LEX_STRING>  definers_list;

  Table_triggers_list(TABLE *table_arg):
    record1_field(0), table(table_arg)
  {
    bzero((char *)bodies, sizeof(bodies));
  }
  ~Table_triggers_list();

  bool create_trigger(THD *thd, TABLE_LIST *table,
                      LEX_STRING *definer_user,
                      LEX_STRING *definer_host);
  bool drop_trigger(THD *thd, TABLE_LIST *table);
  bool process_triggers(THD *thd, trg_event_type event,
                        trg_action_time_type time_type,
                        bool old_row_is_record1);
  bool get_trigger_info(THD *thd, trg_event_type event,
                        trg_action_time_type time_type,
                        LEX_STRING *trigger_name, LEX_STRING *trigger_stmt,
                        ulong *sql_mode,
                        LEX_STRING *definer);

  static bool check_n_load(THD *thd, const char *db, const char *table_name,
                           TABLE *table, bool names_only);
  static bool drop_all_triggers(THD *thd, char *db, char *table_name);

  bool has_delete_triggers()
  {
    return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
            bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]);
  }

  bool has_before_update_triggers()
  {
    return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]);
  }

  inline bool is_special_var_used(int event, int action_time) const
  {
    return m_spec_var_used[event][action_time];
  }

  void set_table(TABLE *new_table);

  friend class Item_trigger_field;
  friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
                Table_triggers_list *triggers);

private:
  bool prepare_record1_accessors(TABLE *table);
};

extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];