mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Fix for bug#19634 "Re-execution of multi-delete which involve trigger/stored
function crashes server". Attempts to execute prepared multi-delete statement which involved trigger or stored function caused server crashes (the same happened for such statements included in stored procedures in cases when one tried to execute them more than once). The problem was caused by yet another incorrect usage of check_table_access() routine (the latter assumes that table list which it gets as argument corresponds to value LEX::query_tables_own_last). We solve this problem by juggling with LEX::query_tables_own_last value when we call check_table_access() for LEX::auxilliary_table_list (better solution is too intrusive and should be done in 5.1). mysql-test/r/sp-prelocking.result: Added test for bug#19634 "Re-execution of multi-delete which involve trigger/ stored function crashes server". mysql-test/t/sp-prelocking.test: Added test for bug#19634 "Re-execution of multi-delete which involve trigger/ stored function crashes server". sql/sql_parse.cc: To call safely check_table_access() for LEX::auxilliary_table_list we have to juggle with LEX::query_tables_own_last value.
This commit is contained in:
parent
375a189451
commit
e9452db1c1
3 changed files with 85 additions and 4 deletions
|
@ -237,3 +237,21 @@ deallocate prepare stmt;
|
|||
drop table t1;
|
||||
drop view v1, v2, v3;
|
||||
drop function bug15683;
|
||||
drop table if exists t1, t2, t3;
|
||||
drop function if exists bug19634;
|
||||
create table t1 (id int, data int);
|
||||
create table t2 (id int);
|
||||
create table t3 (data int);
|
||||
create function bug19634() returns int return (select count(*) from t3);
|
||||
prepare stmt from "delete t1 from t1, t2 where t1.id = t2.id and bug19634()";
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
create trigger t1_bi before delete on t1 for each row insert into t3 values (old.data);
|
||||
prepare stmt from "delete t1 from t1, t2 where t1.id = t2.id";
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
drop function bug19634;
|
||||
drop table t1, t2, t3;
|
||||
End of 5.0 tests
|
||||
|
|
|
@ -272,3 +272,34 @@ drop table t1;
|
|||
drop view v1, v2, v3;
|
||||
drop function bug15683;
|
||||
|
||||
|
||||
#
|
||||
# Bug#19634 "Re-execution of multi-delete which involve trigger/stored
|
||||
# function crashes server"
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2, t3;
|
||||
drop function if exists bug19634;
|
||||
--enable_warnings
|
||||
create table t1 (id int, data int);
|
||||
create table t2 (id int);
|
||||
create table t3 (data int);
|
||||
create function bug19634() returns int return (select count(*) from t3);
|
||||
prepare stmt from "delete t1 from t1, t2 where t1.id = t2.id and bug19634()";
|
||||
# This should not crash server
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
|
||||
create trigger t1_bi before delete on t1 for each row insert into t3 values (old.data);
|
||||
prepare stmt from "delete t1 from t1, t2 where t1.id = t2.id";
|
||||
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
|
||||
drop function bug19634;
|
||||
drop table t1, t2, t3;
|
||||
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
|
|
@ -5202,8 +5202,26 @@ bool check_global_access(THD *thd, ulong want_access)
|
|||
|
||||
|
||||
/*
|
||||
Check the privilege for all used tables. Table privileges are cached
|
||||
in the table list for GRANT checking
|
||||
Check the privilege for all used tables.
|
||||
|
||||
SYNOPSYS
|
||||
check_table_access()
|
||||
thd Thread context
|
||||
want_access Privileges requested
|
||||
tables List of tables to be checked
|
||||
no_errors FALSE/TRUE - report/don't report error to
|
||||
the client (using my_error() call).
|
||||
|
||||
NOTES
|
||||
Table privileges are cached in the table list for GRANT checking.
|
||||
This functions assumes that table list used and
|
||||
thd->lex->query_tables_own_last value correspond to each other
|
||||
(the latter should be either 0 or point to next_global member
|
||||
of one of elements of this table list).
|
||||
|
||||
RETURN VALUE
|
||||
FALSE - OK
|
||||
TRUE - Access denied
|
||||
*/
|
||||
|
||||
bool
|
||||
|
@ -7068,14 +7086,28 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
|
|||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||
TABLE_LIST *aux_tables=
|
||||
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
|
||||
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
|
||||
DBUG_ENTER("multi_delete_precheck");
|
||||
|
||||
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
||||
DBUG_ASSERT(aux_tables != 0);
|
||||
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
|
||||
check_table_access(thd,SELECT_ACL, tables,0) ||
|
||||
check_table_access(thd,DELETE_ACL, aux_tables,0))
|
||||
check_table_access(thd, SELECT_ACL, tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/*
|
||||
Since aux_tables list is not part of LEX::query_tables list we
|
||||
have to juggle with LEX::query_tables_own_last value to be able
|
||||
call check_table_access() safely.
|
||||
*/
|
||||
thd->lex->query_tables_own_last= 0;
|
||||
if (check_table_access(thd, DELETE_ACL, aux_tables, 0))
|
||||
{
|
||||
thd->lex->query_tables_own_last= save_query_tables_own_last;
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
thd->lex->query_tables_own_last= save_query_tables_own_last;
|
||||
|
||||
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
|
||||
{
|
||||
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
|
||||
|
|
Loading…
Reference in a new issue