summaryrefslogtreecommitdiff
path: root/sql/sql_trigger.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_trigger.cc')
-rw-r--r--sql/sql_trigger.cc237
1 files changed, 121 insertions, 116 deletions
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index d4fab80a82a..df363c3c21c 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -21,7 +21,7 @@
#include "parse_file.h"
static const LEX_STRING triggers_file_type=
- {(char *) STRING_WITH_LEN("TRIGGERS")};
+ { C_STRING_WITH_LEN("TRIGGERS") };
const char * const triggers_file_ext= ".TRG";
@@ -34,17 +34,17 @@ const char * const triggers_file_ext= ".TRG";
static File_option triggers_file_parameters[]=
{
{
- {(char *) STRING_WITH_LEN("triggers") },
+ { C_STRING_WITH_LEN("triggers") },
my_offsetof(class Table_triggers_list, definitions_list),
FILE_OPTIONS_STRLIST
},
{
- {(char *) STRING_WITH_LEN("sql_modes") },
+ { C_STRING_WITH_LEN("sql_modes") },
my_offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST
},
{
- {(char *) STRING_WITH_LEN("definers") },
+ { C_STRING_WITH_LEN("definers") },
my_offsetof(class Table_triggers_list, definers_list),
FILE_OPTIONS_STRLIST
},
@@ -53,7 +53,7 @@ static File_option triggers_file_parameters[]=
File_option sql_modes_parameters=
{
- {(char*) STRING_WITH_LEN("sql_modes") },
+ { C_STRING_WITH_LEN("sql_modes") },
my_offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST
};
@@ -77,14 +77,14 @@ struct st_trigname
};
static const LEX_STRING trigname_file_type=
- {(char *) STRING_WITH_LEN("TRIGGERNAME")};
+ { C_STRING_WITH_LEN("TRIGGERNAME") };
const char * const trigname_file_ext= ".TRN";
static File_option trigname_file_parameters[]=
{
{
- {(char *) STRING_WITH_LEN("trigger_table")},
+ { C_STRING_WITH_LEN("trigger_table")},
offsetof(struct st_trigname, trigger_table),
FILE_OPTIONS_ESTRING
},
@@ -94,15 +94,15 @@ static File_option trigname_file_parameters[]=
const LEX_STRING trg_action_time_type_names[]=
{
- { (char *) STRING_WITH_LEN("BEFORE") },
- { (char *) STRING_WITH_LEN("AFTER") }
+ { C_STRING_WITH_LEN("BEFORE") },
+ { C_STRING_WITH_LEN("AFTER") }
};
const LEX_STRING trg_event_type_names[]=
{
- { (char *) STRING_WITH_LEN("INSERT") },
- { (char *) STRING_WITH_LEN("UPDATE") },
- { (char *) STRING_WITH_LEN("DELETE") }
+ { C_STRING_WITH_LEN("INSERT") },
+ { C_STRING_WITH_LEN("UPDATE") },
+ { C_STRING_WITH_LEN("DELETE") }
};
@@ -199,14 +199,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
/*
- TODO: We should check if user has TRIGGER privilege for table here.
- Now we just require SUPER privilege for creating/dropping because
- we don't have proper privilege checking for triggers in place yet.
- */
- if (check_global_access(thd, SUPER_ACL))
- DBUG_RETURN(TRUE);
-
- /*
There is no DETERMINISTIC clause for triggers, so can't check it.
But a trigger can in theory be used to do nasty things (if it supported
DROP for example) so we do the check for privileges. For now there is
@@ -259,6 +251,22 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
}
+ /*
+ Check that the user has TRIGGER privilege on the subject table.
+ */
+ {
+ bool err_status;
+ TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
+ thd->lex->query_tables_own_last= 0;
+
+ err_status= check_table_access(thd, TRIGGER_ACL, tables, 0);
+
+ thd->lex->query_tables_own_last= save_query_tables_own_last;
+
+ if (err_status)
+ goto end;
+ }
+
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
@@ -307,9 +315,8 @@ end:
thd->clear_error();
/* Such a statement can always go directly to binlog, no trans cache. */
- Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0,
- FALSE);
- mysql_bin_log.write(&qinfo);
+ thd->binlog_query(THD::STMT_QUERY_TYPE,
+ stmt_query.ptr(), stmt_query.length(), FALSE, FALSE);
}
}
@@ -352,9 +359,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- char dir_buff[FN_REFLEN], file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
- trigname_path[FN_REFLEN];
- LEX_STRING dir, file, trigname_file;
+ char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
+ LEX_STRING file, trigname_file;
LEX_STRING *trg_def;
LEX_STRING definer_user;
LEX_STRING definer_host;
@@ -366,7 +372,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Trigger must be in the same schema as target table. */
- if (my_strcasecmp(table_alias_charset, table->s->db, lex->spname->m_db.str))
+ if (my_strcasecmp(table_alias_charset, table->s->db.str,
+ lex->spname->m_db.str))
{
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
return 1;
@@ -460,20 +467,18 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
sql_create_definition_file() files handles renaming and backup of older
versions
*/
- strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db, "/", NullS);
- dir.length= unpack_filename(dir_buff, dir_buff);
- dir.str= dir_buff;
- file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name,
- triggers_file_ext, NullS) - file_buff;
+ file.length= build_table_filename(file_buff, FN_REFLEN-1,
+ tables->db, tables->table_name,
+ triggers_file_ext, 0);
file.str= file_buff;
- trigname_file.length= strxnmov(trigname_buff, FN_REFLEN,
- lex->spname->m_name.str,
- trigname_file_ext, NullS) - trigname_buff;
+ trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
+ tables->db,
+ lex->spname->m_name.str,
+ trigname_file_ext, 0);
trigname_file.str= trigname_buff;
- strxnmov(trigname_path, FN_REFLEN, dir_buff, trigname_buff, NullS);
/* Use the filesystem to enforce trigger namespace constraints. */
- if (!access(trigname_path, F_OK))
+ if (!access(trigname_buff, F_OK))
{
my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
return 1;
@@ -482,7 +487,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
trigname.trigger_table.str= tables->table_name;
trigname.trigger_table.length= tables->table_name_length;
- if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type,
+ if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
(gptr)&trigname, trigname_file_parameters, 0))
return 1;
@@ -572,12 +577,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Create trigger definition file. */
- if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
+ if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 0))
return 0;
err_with_cleanup:
- my_delete(trigname_path, MYF(MY_WME));
+ my_delete(trigname_buff, MYF(MY_WME));
return 1;
}
@@ -600,9 +605,7 @@ err_with_cleanup:
static bool rm_trigger_file(char *path, const char *db,
const char *table_name)
{
- strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
- triggers_file_ext, NullS);
- unpack_filename(path, path);
+ build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -625,9 +628,8 @@ static bool rm_trigger_file(char *path, const char *db,
static bool rm_trigname_file(char *path, const char *db,
const char *trigger_name)
{
- strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", trigger_name,
- trigname_file_ext, NullS);
- unpack_filename(path, path);
+ build_table_filename(path, FN_REFLEN-1,
+ db, trigger_name, trigname_file_ext, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -649,18 +651,15 @@ static bool rm_trigname_file(char *path, const char *db,
static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
const char *table_name)
{
- char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
- LEX_STRING dir, file;
-
- strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", db, "/", NullS);
- dir.length= unpack_filename(dir_buff, dir_buff);
- dir.str= dir_buff;
- file.length= strxnmov(file_buff, FN_REFLEN, table_name, triggers_file_ext,
- NullS) - file_buff;
- file.str= file_buff;
+ char file_buff[FN_REFLEN];
+ LEX_STRING file;
- return sql_create_definition_file(&dir, &file, &triggers_file_type,
- (gptr)triggers, triggers_file_parameters, 0);
+ file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
+ triggers_file_ext, 0);
+ file.str= file_buff;
+ return sql_create_definition_file(NULL, &file, &triggers_file_type,
+ (gptr)triggers, triggers_file_parameters,
+ 0);
}
@@ -781,8 +780,8 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
if (!(*old_fld= (*fld)->new_field(&table->mem_root, table,
table == (*fld)->table)))
return 1;
- (*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
- table->record[0]));
+ (*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
+ table->record[0]));
}
*old_fld= 0;
@@ -836,9 +835,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_ENTER("Table_triggers_list::check_n_load");
- strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
- triggers_file_ext, NullS);
- path.length= unpack_filename(path_buff, path_buff);
+ path.length= build_table_filename(path_buff, FN_REFLEN-1,
+ db, table_name, triggers_file_ext, 0);
path.str= path_buff;
// QQ: should we analyze errno somehow ?
@@ -1018,7 +1016,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
schema.
*/
- lex.sphead->set_definer("", 0);
+ lex.sphead->set_definer((char*) "", 0);
/*
Triggers without definer information are executed under the
@@ -1197,9 +1195,9 @@ add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
DBUG_ENTER("add_table_for_trigger");
DBUG_ASSERT(table != NULL);
- strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", trig->m_db.str, "/",
- trig->m_name.str, trigname_file_ext, NullS);
- path.length= unpack_filename(path_buff, path_buff);
+ path.length= build_table_filename(path_buff, FN_REFLEN-1,
+ trig->m_db.str, trig->m_name.str,
+ trigname_file_ext, 0);
path.str= path_buff;
if (access(path_buff, F_OK))
@@ -1411,26 +1409,24 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
LEX_STRING *new_table_name,
LEX_STRING *stopper)
{
- char dir_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
+ char trigname_buff[FN_REFLEN];
struct st_trigname trigname;
- LEX_STRING dir, trigname_file;
+ LEX_STRING trigname_file;
LEX_STRING *trigger;
List_iterator_fast<LEX_STRING> it_name(names_list);
- strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", db_name, "/", NullS);
- dir.length= unpack_filename(dir_buff, dir_buff);
- dir.str= dir_buff;
-
while ((trigger= it_name++) != stopper)
{
- trigname_file.length= strxnmov(trigname_buff, FN_REFLEN, trigger->str,
- trigname_file_ext, NullS) - trigname_buff;
+ trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
+ db_name, trigger->str,
+ trigname_file_ext, 0);
trigname_file.str= trigname_buff;
trigname.trigger_table= *new_table_name;
- if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type,
- (gptr)&trigname, trigname_file_parameters, 0))
+ if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
+ (gptr)&trigname, trigname_file_parameters,
+ 0))
return trigger;
}
@@ -1485,8 +1481,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
}
if (table.triggers)
{
- LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
- LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+ LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+ LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
/*
Since triggers should be in the same schema as their subject tables
moving table with them between two schemas raises too many questions.
@@ -1553,12 +1549,48 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
new_field= record1_field;
old_field= trigger_table->field;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_ctx;
+
+ if (sp_change_security_context(thd, sp_trigger, &save_ctx))
+ return TRUE;
+
+ /*
+ Fetch information about table-level privileges to GRANT_INFO structure for
+ subject table. Check of privileges that will use it and information about
+ column-level privileges will happen in Item_trigger_field::fix_fields().
+ */
+
+ fill_effective_table_privileges(thd,
+ &subject_table_grants[event][time_type],
+ trigger_table->s->db.str,
+ trigger_table->s->table_name.str);
+
+ /* Check that the definer has TRIGGER privilege on the subject table. */
+
+ if (!(subject_table_grants[event][time_type].privilege & TRIGGER_ACL))
+ {
+ char priv_desc[128];
+ get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL);
+
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
+ thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
+ trigger_table->s->table_name.str);
+
+ sp_restore_security_context(thd, save_ctx);
+ return TRUE;
+ }
+#endif // NO_EMBEDDED_ACCESS_CHECKS
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
err_status= sp_trigger->execute_trigger
- (thd, trigger_table->s->db, trigger_table->s->table_name,
+ (thd, trigger_table->s->db.str, trigger_table->s->table_name.str,
&subject_table_grants[event][time_type]);
thd->restore_sub_statement_state(&statement_state);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ sp_restore_security_context(thd, save_ctx);
+#endif // NO_EMBEDDED_ACCESS_CHECKS
}
return err_status;
@@ -1575,12 +1607,12 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
DESCRIPTION
This method marks fields of subject table which are read/set in its
- triggers as such (by setting Field::query_id equal to THD::query_id)
+ triggers as such (by properly updating TABLE::read_set/write_set)
and thus informs handler that values for these fields should be
retrieved/stored during execution of statement.
*/
-void Table_triggers_list::mark_fields_used(THD *thd, trg_event_type event)
+void Table_triggers_list::mark_fields_used(trg_event_type event)
{
int action_time;
Item_trigger_field *trg_field;
@@ -1592,41 +1624,14 @@ void Table_triggers_list::mark_fields_used(THD *thd, trg_event_type event)
{
/* We cannot mark fields which does not present in table. */
if (trg_field->field_idx != (uint)-1)
- trigger_table->field[trg_field->field_idx]->query_id = thd->query_id;
+ {
+ bitmap_set_bit(trigger_table->read_set, trg_field->field_idx);
+ if (trg_field->get_settable_routine_parameter())
+ bitmap_set_bit(trigger_table->write_set, trg_field->field_idx);
+ }
}
}
-}
-
-
-/*
- Check if field of subject table can be changed in before update trigger.
-
- SYNOPSIS
- is_updated_in_before_update_triggers()
- field Field object for field to be checked
-
- NOTE
- Field passed to this function should be bound to the same
- TABLE object as Table_triggers_list.
-
- RETURN VALUE
- TRUE Field is changed
- FALSE Otherwise
-*/
-
-bool Table_triggers_list::is_updated_in_before_update_triggers(Field *fld)
-{
- Item_trigger_field *trg_fld;
- for (trg_fld= trigger_fields[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE];
- trg_fld != 0;
- trg_fld= trg_fld->next_trg_field)
- {
- if (trg_fld->get_settable_routine_parameter() &&
- trg_fld->field_idx != (uint)-1 &&
- trigger_table->field[trg_fld->field_idx]->eq(fld))
- return TRUE;
- }
- return FALSE;
+ trigger_table->file->column_bitmaps_signal();
}
@@ -1659,7 +1664,7 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
char *end)
{
DBUG_ENTER("Handle_old_incorrect_sql_modes_hook::process_unknown_string");
- DBUG_PRINT("info", ("unknown key:%60s", unknown_key));
+ DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end &&
unknown_key[INVALID_SQL_MODES_LENGTH] == '=' &&
@@ -1701,7 +1706,7 @@ process_unknown_string(char *&unknown_key, gptr base, MEM_ROOT *mem_root,
char *end)
{
DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string");
- DBUG_PRINT("info", ("unknown key:%60s", unknown_key));
+ DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
if (unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1 < end &&
unknown_key[INVALID_TRIGGER_TABLE_LENGTH] == '=' &&