mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
WL#2818 (Add creator to the trigger definition for privilege
checks on trigger activation) mysql-test/r/information_schema.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/mysqldump.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/rpl_ddl.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/rpl_sp.result: Update result file: a new clause DEFINER has been added to CREATE TRIGGER statement. mysql-test/r/rpl_trigger.result: Results for new test cases were added. mysql-test/r/skip_grants.result: Error message has been changed. mysql-test/r/trigger.result: Added DEFINER column. mysql-test/r/view.result: Error messages have been changed. mysql-test/r/view_grant.result: Error messages have been changed. mysql-test/t/mysqldump.test: Drop created procedure to not affect further tests. mysql-test/t/rpl_trigger.test: Add tests for new column in information schema. mysql-test/t/skip_grants.test: Error tag has been renamed. mysql-test/t/view.test: Error tag has been renamed. mysql-test/t/view_grant.test: Error tag has been changed. sql/item_func.cc: Fix typo in comments. sql/mysql_priv.h: A try to minimize copy&paste: - introduce operations to be used from sql_yacc.yy; - introduce an operation to be used from trigger and view processing code. sql/share/errmsg.txt: - Rename ER_NO_VIEW_USER to ER_MALFORMED_DEFINER in order to be shared for view and trigger implementations; - Fix a typo; - Add a new error code for trigger warning. sql/sp.cc: set_info() was split into set_info() and set_definer(). sql/sp_head.cc: set_info() was split into set_info() and set_definer(). sql/sp_head.h: set_info() was split into set_info() and set_definer(). sql/sql_acl.cc: Add a new check: exit from the cycle if the table is NULL. sql/sql_lex.h: - Rename create_view_definer to definer, since it is used for views and triggers; - Change st_lex_user to LEX_USER, since st_lex_user is a structure. So, formally, it should be "struct st_lex_user", which is longer than just LEX_USER; - Add trigger_definition_begin. sql/sql_parse.cc: - Add a new check: exit from the cycle if the table is NULL; - Implement definer-related functions. sql/sql_show.cc: Add DEFINER column. sql/sql_trigger.cc: Add DEFINER support for triggers. sql/sql_trigger.h: Add DEFINER support for triggers. sql/sql_view.cc: Rename create_view_definer to definer. sql/sql_yacc.yy: Add support for DEFINER-clause in CREATE TRIGGER statement. Since CREATE TRIGGER and CREATE VIEW can be similar at the start, yacc is unable to distinguish between them. So, had to modify both statements in order to make it parsable by yacc. mysql-test/r/trigger-compat.result: Result file for triggers backward compatibility test. mysql-test/r/trigger-grant.result: Result file of the test for WL#2818. mysql-test/t/trigger-compat.test: Triggers backward compatibility test: check that the server still can load triggers w/o definer attribute and modify tables with such triggers (add a new trigger, etc). mysql-test/t/trigger-grant.test: Test for WL#2818 -- check that DEFINER support in triggers works properly
This commit is contained in:
@ -32,15 +32,36 @@ const char * const triggers_file_ext= ".TRG";
|
||||
*/
|
||||
static File_option triggers_file_parameters[]=
|
||||
{
|
||||
{{(char*)"triggers", 8},
|
||||
{
|
||||
{ (char *) STRING_WITH_LEN("triggers") },
|
||||
offsetof(class Table_triggers_list, definitions_list),
|
||||
FILE_OPTIONS_STRLIST},
|
||||
{{(char*)"sql_modes", 13},
|
||||
FILE_OPTIONS_STRLIST
|
||||
},
|
||||
{
|
||||
/*
|
||||
FIXME: Length specified for "sql_modes" key is erroneous, problem caused
|
||||
by this are reported as BUG#14090 and should be fixed ASAP.
|
||||
*/
|
||||
{ (char *) "sql_modes", 13 },
|
||||
offsetof(class Table_triggers_list, definition_modes_list),
|
||||
FILE_OPTIONS_ULLLIST},
|
||||
{{0, 0}, 0, FILE_OPTIONS_STRING}
|
||||
FILE_OPTIONS_ULLLIST
|
||||
},
|
||||
{
|
||||
{ (char *) STRING_WITH_LEN("definers") },
|
||||
offsetof(class Table_triggers_list, definers_list),
|
||||
FILE_OPTIONS_STRLIST
|
||||
},
|
||||
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
|
||||
};
|
||||
|
||||
/*
|
||||
This must be kept up to date whenever a new option is added to the list
|
||||
above, as it specifies the number of required parameters of the trigger in
|
||||
.trg file.
|
||||
*/
|
||||
|
||||
static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
|
||||
static const int TRG_MAX_VERSIONS= 3;
|
||||
|
||||
/*
|
||||
Structure representing contents of .TRN file which are used to support
|
||||
@ -58,9 +79,16 @@ const char * const trigname_file_ext= ".TRN";
|
||||
|
||||
static File_option trigname_file_parameters[]=
|
||||
{
|
||||
{{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table),
|
||||
FILE_OPTIONS_ESTRING},
|
||||
{{0, 0}, 0, FILE_OPTIONS_STRING}
|
||||
{
|
||||
/*
|
||||
FIXME: Length specified for "trigger_table" key is erroneous, problem
|
||||
caused by this are reported as BUG#14090 and should be fixed ASAP.
|
||||
*/
|
||||
{ (char *) "trigger_table", 15 },
|
||||
offsetof(struct st_trigname, trigger_table),
|
||||
FILE_OPTIONS_ESTRING
|
||||
},
|
||||
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
|
||||
};
|
||||
|
||||
|
||||
@ -104,6 +132,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
{
|
||||
TABLE *table;
|
||||
bool result= TRUE;
|
||||
LEX_STRING definer_user;
|
||||
LEX_STRING definer_host;
|
||||
|
||||
DBUG_ENTER("mysql_create_or_drop_trigger");
|
||||
|
||||
/*
|
||||
@ -184,7 +215,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
}
|
||||
|
||||
result= (create ?
|
||||
table->triggers->create_trigger(thd, tables):
|
||||
table->triggers->create_trigger(thd, tables, &definer_user, &definer_host):
|
||||
table->triggers->drop_trigger(thd, tables));
|
||||
|
||||
end:
|
||||
@ -192,17 +223,30 @@ end:
|
||||
start_waiting_global_read_lock(thd);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
thd->clear_error();
|
||||
|
||||
String log_query(thd->query, thd->query_length, system_charset_info);
|
||||
|
||||
if (create)
|
||||
{
|
||||
thd->clear_error();
|
||||
/* Such a statement can always go directly to binlog, no trans cache */
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */
|
||||
|
||||
log_query.append("CREATE ");
|
||||
append_definer(thd, &log_query, &definer_user, &definer_host);
|
||||
log_query.append(thd->lex->trigger_definition_begin);
|
||||
}
|
||||
send_ok(thd);
|
||||
|
||||
/* Such a statement can always go directly to binlog, no trans cache. */
|
||||
Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
|
||||
send_ok(thd);
|
||||
}
|
||||
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
@ -212,15 +256,26 @@ end:
|
||||
|
||||
SYNOPSIS
|
||||
create_trigger()
|
||||
thd - current thread context (including trigger definition in LEX)
|
||||
tables - table list containing one open table for which trigger is
|
||||
created.
|
||||
thd - current thread context (including trigger definition in
|
||||
LEX)
|
||||
tables - table list containing one open table for which the
|
||||
trigger is created.
|
||||
definer_user - [out] after a call it points to 0-terminated string,
|
||||
which contains user name part of the actual trigger
|
||||
definer. The caller is responsible to provide memory for
|
||||
storing LEX_STRING object.
|
||||
definer_host - [out] after a call it points to 0-terminated string,
|
||||
which contains host name part of the actual trigger
|
||||
definer. The caller is responsible to provide memory for
|
||||
storing LEX_STRING object.
|
||||
|
||||
RETURN VALUE
|
||||
False - success
|
||||
True - error
|
||||
*/
|
||||
bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
|
||||
bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
||||
LEX_STRING *definer_user,
|
||||
LEX_STRING *definer_host)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE *table= tables->table;
|
||||
@ -229,6 +284,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
|
||||
LEX_STRING dir, file, trigname_file;
|
||||
LEX_STRING *trg_def, *name;
|
||||
ulonglong *trg_sql_mode;
|
||||
char trg_definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2];
|
||||
LEX_STRING *trg_definer;
|
||||
Item_trigger_field *trg_field;
|
||||
struct st_trigname trigname;
|
||||
|
||||
@ -249,6 +306,31 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Definer attribute of the Lex instance is always set in sql_yacc.yy when
|
||||
trigger is created.
|
||||
*/
|
||||
|
||||
DBUG_ASSERT(lex->definer);
|
||||
|
||||
/*
|
||||
If the specified definer differs from the current user, we should check
|
||||
that the current user has SUPER privilege (in order to create trigger
|
||||
under another user one must have SUPER privilege).
|
||||
*/
|
||||
|
||||
if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
|
||||
my_strcasecmp(system_charset_info,
|
||||
lex->definer->host.str,
|
||||
thd->security_ctx->priv_host))
|
||||
{
|
||||
if (check_global_access(thd, SUPER_ACL))
|
||||
{
|
||||
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Let us check if all references to fields in old/new versions of row in
|
||||
this trigger are ok.
|
||||
@ -318,15 +400,39 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
|
||||
definitions_list.push_back(trg_def, &table->mem_root) ||
|
||||
!(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root,
|
||||
sizeof(ulonglong))) ||
|
||||
definition_modes_list.push_back(trg_sql_mode, &table->mem_root))
|
||||
definition_modes_list.push_back(trg_sql_mode, &table->mem_root) ||
|
||||
!(trg_definer= (LEX_STRING*) alloc_root(&table->mem_root,
|
||||
sizeof(LEX_STRING))) ||
|
||||
definers_list.push_back(trg_definer, &table->mem_root))
|
||||
goto err_with_cleanup;
|
||||
|
||||
trg_def->str= thd->query;
|
||||
trg_def->length= thd->query_length;
|
||||
*trg_sql_mode= thd->variables.sql_mode;
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (!is_acl_user(lex->definer->host.str,
|
||||
lex->definer->user.str))
|
||||
{
|
||||
push_warning_printf(thd,
|
||||
MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_NO_SUCH_USER,
|
||||
ER(ER_NO_SUCH_USER),
|
||||
lex->definer->user.str,
|
||||
lex->definer->host.str);
|
||||
}
|
||||
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||
|
||||
*definer_user= lex->definer->user;
|
||||
*definer_host= lex->definer->host;
|
||||
|
||||
trg_definer->str= trg_definer_holder;
|
||||
trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
|
||||
definer_host->str, NullS) - trg_definer->str;
|
||||
|
||||
if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
|
||||
(gptr)this, triggers_file_parameters, 3))
|
||||
(gptr)this, triggers_file_parameters,
|
||||
TRG_MAX_VERSIONS))
|
||||
return 0;
|
||||
|
||||
err_with_cleanup:
|
||||
@ -403,12 +509,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
|
||||
List_iterator_fast<LEX_STRING> it_name(names_list);
|
||||
List_iterator<LEX_STRING> it_def(definitions_list);
|
||||
List_iterator<ulonglong> it_mod(definition_modes_list);
|
||||
List_iterator<LEX_STRING> it_definer(definers_list);
|
||||
char path[FN_REFLEN];
|
||||
|
||||
while ((name= it_name++))
|
||||
{
|
||||
it_def++;
|
||||
it_mod++;
|
||||
it_definer++;
|
||||
|
||||
if (my_strcasecmp(table_alias_charset, lex->spname->m_name.str,
|
||||
name->str) == 0)
|
||||
@ -419,6 +527,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
|
||||
*/
|
||||
it_def.remove();
|
||||
it_mod.remove();
|
||||
it_definer.remove();
|
||||
|
||||
if (definitions_list.is_empty())
|
||||
{
|
||||
@ -446,7 +555,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
|
||||
|
||||
if (sql_create_definition_file(&dir, &file, &triggers_file_type,
|
||||
(gptr)this, triggers_file_parameters,
|
||||
3))
|
||||
TRG_MAX_VERSIONS))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -568,7 +677,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
DBUG_RETURN(0);
|
||||
|
||||
/*
|
||||
File exists so we got to load triggers
|
||||
File exists so we got to load triggers.
|
||||
FIXME: A lot of things to do here e.g. how about other funcs and being
|
||||
more paranoical ?
|
||||
*/
|
||||
@ -584,13 +693,16 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/*
|
||||
We don't have sql_modes in old versions of .TRG file, so we should
|
||||
initialize list for safety.
|
||||
We don't have the following attributes in old versions of .TRG file, so
|
||||
we should initialize the list for safety:
|
||||
- sql_modes;
|
||||
- definers;
|
||||
*/
|
||||
triggers->definition_modes_list.empty();
|
||||
triggers->definers_list.empty();
|
||||
|
||||
if (parser->parse((gptr)triggers, &table->mem_root,
|
||||
triggers_file_parameters, 2))
|
||||
triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
|
||||
@ -612,7 +724,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
DBUG_RETURN(1); // EOM
|
||||
}
|
||||
*trg_sql_mode= global_system_variables.sql_mode;
|
||||
while ((trg_create_str= it++))
|
||||
while (it++)
|
||||
{
|
||||
if (triggers->definition_modes_list.push_back(trg_sql_mode,
|
||||
&table->mem_root))
|
||||
@ -623,8 +735,43 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
it.rewind();
|
||||
}
|
||||
|
||||
if (triggers->definers_list.is_empty() &&
|
||||
!triggers->definitions_list.is_empty())
|
||||
{
|
||||
/*
|
||||
It is old file format => we should fill list of definers.
|
||||
|
||||
If there is no definer information, we should not switch context to
|
||||
definer when checking privileges. I.e. privileges for such triggers
|
||||
are checked for "invoker" rather than for "definer".
|
||||
*/
|
||||
|
||||
LEX_STRING *trg_definer;
|
||||
|
||||
if (! (trg_definer= (LEX_STRING*)alloc_root(&table->mem_root,
|
||||
sizeof(LEX_STRING))))
|
||||
DBUG_RETURN(1); // EOM
|
||||
|
||||
trg_definer->str= "";
|
||||
trg_definer->length= 0;
|
||||
|
||||
while (it++)
|
||||
{
|
||||
if (triggers->definers_list.push_back(trg_definer,
|
||||
&table->mem_root))
|
||||
{
|
||||
DBUG_RETURN(1); // EOM
|
||||
}
|
||||
}
|
||||
|
||||
it.rewind();
|
||||
}
|
||||
|
||||
DBUG_ASSERT(triggers->definition_modes_list.elements ==
|
||||
triggers->definitions_list.elements);
|
||||
DBUG_ASSERT(triggers->definers_list.elements ==
|
||||
triggers->definitions_list.elements);
|
||||
|
||||
table->triggers= triggers;
|
||||
|
||||
/*
|
||||
@ -647,6 +794,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
|
||||
char *trg_name_buff;
|
||||
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
||||
List_iterator_fast<LEX_STRING> it_definer(triggers->
|
||||
definers_list);
|
||||
LEX *old_lex= thd->lex, lex;
|
||||
ulong save_sql_mode= thd->variables.sql_mode;
|
||||
|
||||
@ -659,22 +808,55 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
while ((trg_create_str= it++))
|
||||
{
|
||||
trg_sql_mode= itm++;
|
||||
LEX_STRING *trg_definer= it_definer++;
|
||||
thd->variables.sql_mode= (ulong)*trg_sql_mode;
|
||||
lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
|
||||
|
||||
if (yyparse((void *)thd) || thd->is_fatal_error)
|
||||
{
|
||||
/*
|
||||
Free lex associated resources
|
||||
Free lex associated resources.
|
||||
QQ: Do we really need all this stuff here ?
|
||||
*/
|
||||
delete lex.sphead;
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
|
||||
lex.sphead->m_sql_mode= *trg_sql_mode;
|
||||
lex.sphead->set_info(0, 0, &lex.sp_chistics, *trg_sql_mode);
|
||||
|
||||
triggers->bodies[lex.trg_chistics.event]
|
||||
[lex.trg_chistics.action_time]= lex.sphead;
|
||||
|
||||
if (!trg_definer->length)
|
||||
{
|
||||
/*
|
||||
This trigger was created/imported from the previous version of
|
||||
MySQL, which does not support triggers definers. We should emit
|
||||
warning here.
|
||||
*/
|
||||
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
|
||||
(const char*) db,
|
||||
(const char*) lex.sphead->m_name.str);
|
||||
|
||||
/*
|
||||
Set definer to the '' to correct displaying in the information
|
||||
schema.
|
||||
*/
|
||||
|
||||
lex.sphead->set_definer("", 0);
|
||||
|
||||
/*
|
||||
Triggers without definer information are executed under the
|
||||
authorization of the invoker.
|
||||
*/
|
||||
|
||||
lex.sphead->m_chistics->suid= SP_IS_NOT_SUID;
|
||||
}
|
||||
else
|
||||
lex.sphead->set_definer(trg_definer->str, trg_definer->length);
|
||||
|
||||
if (triggers->names_list.push_back(&lex.sphead->m_name,
|
||||
&table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
@ -701,6 +883,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
trg_field= trg_field->next_trg_field)
|
||||
trg_field->setup_field(thd, table);
|
||||
|
||||
triggers->m_spec_var_used[lex.trg_chistics.event]
|
||||
[lex.trg_chistics.action_time]=
|
||||
lex.trg_table_fields.first ? TRUE : FALSE;
|
||||
|
||||
lex_end(&lex);
|
||||
}
|
||||
thd->db= save_db.str;
|
||||
@ -744,6 +930,9 @@ err_with_lex_cleanup:
|
||||
name - returns name of trigger
|
||||
stmt - returns statement of trigger
|
||||
sql_mode - returns sql_mode of trigger
|
||||
definer_user - returns definer/creator of trigger. The caller is
|
||||
responsible to allocate enough space for storing definer
|
||||
information.
|
||||
|
||||
RETURN VALUE
|
||||
False - success
|
||||
@ -754,7 +943,8 @@ bool Table_triggers_list::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)
|
||||
ulong *sql_mode,
|
||||
LEX_STRING *definer)
|
||||
{
|
||||
sp_head *body;
|
||||
DBUG_ENTER("get_trigger_info");
|
||||
@ -763,6 +953,18 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
|
||||
*trigger_name= body->m_name;
|
||||
*trigger_stmt= body->m_body;
|
||||
*sql_mode= body->m_sql_mode;
|
||||
|
||||
if (body->m_chistics->suid == SP_IS_NOT_SUID)
|
||||
{
|
||||
definer->str[0]= 0;
|
||||
definer->length= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
definer->length= strxmov(definer->str, body->m_definer_user.str, "@",
|
||||
body->m_definer_host.str, NullS) - definer->str;
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
@ -898,8 +1100,9 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||
bool old_row_is_record1)
|
||||
{
|
||||
int res= 0;
|
||||
sp_head *sp_trigger= bodies[event][time_type];
|
||||
|
||||
if (bodies[event][time_type])
|
||||
if (sp_trigger)
|
||||
{
|
||||
Sub_statement_state statement_state;
|
||||
|
||||
@ -914,14 +1117,54 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||
old_field= table->field;
|
||||
}
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *save_ctx;
|
||||
|
||||
if (sp_change_security_context(thd, sp_trigger, &save_ctx))
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
FIXME: We should juggle with security context here (because trigger
|
||||
should be invoked with creator rights).
|
||||
NOTE: TRIGGER_ACL should be used below.
|
||||
*/
|
||||
|
||||
if (check_global_access(thd, SUPER_ACL))
|
||||
{
|
||||
sp_restore_security_context(thd, save_ctx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
If the trigger uses special variables (NEW/OLD), check that we have
|
||||
SELECT and UPDATE privileges on the subject table.
|
||||
*/
|
||||
|
||||
if (is_special_var_used(event, time_type))
|
||||
{
|
||||
TABLE_LIST table_list;
|
||||
bzero((char *) &table_list, sizeof (table_list));
|
||||
table_list.db= (char *) table->s->db;
|
||||
table_list.db_length= strlen(table_list.db);
|
||||
table_list.table_name= (char *) table->s->table_name;
|
||||
table_list.table_name_length= strlen(table_list.table_name);
|
||||
table_list.alias= (char *) table->alias;
|
||||
table_list.table= table;
|
||||
|
||||
if (check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0))
|
||||
{
|
||||
sp_restore_security_context(thd, save_ctx);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
||||
res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
|
||||
res= sp_trigger->execute_function(thd, 0, 0, 0);
|
||||
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 res;
|
||||
|
Reference in New Issue
Block a user