diff options
Diffstat (limited to 'sql/sql_trigger.cc')
-rw-r--r-- | sql/sql_trigger.cc | 237 |
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] == '=' && |