Commit 8482de43 authored by ingo@mysql.com's avatar ingo@mysql.com

Merge mysql.com:/home/mydev/mysql-5.0

into  mysql.com:/home/mydev/mysql-5.0-bug10932
parents 270cad2f 886ac06c
...@@ -1088,3 +1088,43 @@ ERROR 0A000: Not allowed to return a result set from a function ...@@ -1088,3 +1088,43 @@ ERROR 0A000: Not allowed to return a result set from a function
drop table t1| drop table t1|
drop procedure bug13012_1| drop procedure bug13012_1|
drop function bug13012_2| drop function bug13012_2|
drop function if exists bug11555_1;
drop function if exists bug11555_2;
drop view if exists v1, v2, v3, v4;
create function bug11555_1() returns int return (select max(i) from t1);
create function bug11555_2() returns int return bug11555_1();
create view v1 as select bug11555_1();
ERROR 42S02: Table 'test.t1' doesn't exist
create view v2 as select bug11555_2();
ERROR 42S02: Table 'test.t1' doesn't exist
create table t1 (i int);
create view v1 as select bug11555_1();
create view v2 as select bug11555_2();
create view v3 as select * from v1;
drop table t1;
select * from v1;
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
select * from v2;
ERROR HY000: View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
select * from v3;
ERROR HY000: View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
create view v4 as select * from v1;
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
drop view v1, v2, v3;
drop function bug11555_1;
drop function bug11555_2;
create table t1 (i int);
create table t2 (i int);
create trigger t1_ai after insert on t1 for each row insert into t2 values (new.i);
create view v1 as select * from t1;
drop table t2;
insert into v1 values (1);
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
drop trigger t1_ai;
create function bug11555_1() returns int return (select max(i) from t2);
create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
insert into v1 values (2);
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
drop function bug11555_1;
drop table t1;
drop view v1;
...@@ -1933,11 +1933,11 @@ create function f1 () returns int return (select max(col1) from t1); ...@@ -1933,11 +1933,11 @@ create function f1 () returns int return (select max(col1) from t1);
DROP TABLE t1; DROP TABLE t1;
CHECK TABLE v1, v2, v3, v4, v5, v6; CHECK TABLE v1, v2, v3, v4, v5, v6;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.v1 check error Table 'test.t1' doesn't exist test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v2 check status OK test.v2 check status OK
test.v3 check error Table 'test.t1' doesn't exist test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v4 check status OK test.v4 check status OK
test.v5 check error Table 'test.t1' doesn't exist test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
test.v6 check status OK test.v6 check status OK
drop function f1; drop function f1;
drop function f2; drop function f2;
......
...@@ -1556,6 +1556,67 @@ drop procedure bug13012_1| ...@@ -1556,6 +1556,67 @@ drop procedure bug13012_1|
drop function bug13012_2| drop function bug13012_2|
delimiter ;| delimiter ;|
# BUG#11555 "Stored procedures: current SP tables locking make
# impossible view security". We should not expose names of tables
# which are implicitly used by view (via stored routines/triggers).
#
# Note that SQL standard assumes that you simply won't be able drop table
# and leave some objects (routines/views/triggers) which were depending on
# it. Such objects should be dropped in advance (by default) or will be
# dropped simultaneously with table (DROP TABLE with CASCADE clause).
# So these tests probably should go away once we will implement standard
# behavior.
--disable_warnings
drop function if exists bug11555_1;
drop function if exists bug11555_2;
drop view if exists v1, v2, v3, v4;
--enable_warnings
create function bug11555_1() returns int return (select max(i) from t1);
create function bug11555_2() returns int return bug11555_1();
# It is OK to report name of implicitly used table which is missing
# when we create view.
--error ER_NO_SUCH_TABLE
create view v1 as select bug11555_1();
--error ER_NO_SUCH_TABLE
create view v2 as select bug11555_2();
# But we should hide name of missing implicitly used table when we use view
create table t1 (i int);
create view v1 as select bug11555_1();
create view v2 as select bug11555_2();
create view v3 as select * from v1;
drop table t1;
--error ER_VIEW_INVALID
select * from v1;
--error ER_VIEW_INVALID
select * from v2;
--error ER_VIEW_INVALID
select * from v3;
# Note that creation of view which depends on broken view is yet
# another form of view usage.
--error ER_VIEW_INVALID
create view v4 as select * from v1;
drop view v1, v2, v3;
# We also should hide details about broken triggers which are
# invoked for view.
drop function bug11555_1;
drop function bug11555_2;
create table t1 (i int);
create table t2 (i int);
create trigger t1_ai after insert on t1 for each row insert into t2 values (new.i);
create view v1 as select * from t1;
drop table t2;
--error ER_VIEW_INVALID
insert into v1 values (1);
drop trigger t1_ai;
create function bug11555_1() returns int return (select max(i) from t2);
create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
--error ER_VIEW_INVALID
insert into v1 values (2);
drop function bug11555_1;
drop table t1;
drop view v1;
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
#--disable_warnings #--disable_warnings
......
...@@ -1744,7 +1744,6 @@ drop function f1; ...@@ -1744,7 +1744,6 @@ drop function f1;
CHECK TABLE v1, v2, v3, v4, v5, v6; CHECK TABLE v1, v2, v3, v4, v5, v6;
create function f1 () returns int return (select max(col1) from t1); create function f1 () returns int return (select max(col1) from t1);
DROP TABLE t1; DROP TABLE t1;
# following will show underlying table until BUG#11555 fix
CHECK TABLE v1, v2, v3, v4, v5, v6; CHECK TABLE v1, v2, v3, v4, v5, v6;
drop function f1; drop function f1;
drop function f2; drop function f2;
......
...@@ -715,6 +715,7 @@ void free_old_query(MYSQL *mysql) ...@@ -715,6 +715,7 @@ void free_old_query(MYSQL *mysql)
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */ init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
mysql->fields= 0; mysql->fields= 0;
mysql->field_count= 0; /* For API */ mysql->field_count= 0; /* For API */
mysql->warning_count= 0;
mysql->info= 0; mysql->info= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2484,7 +2485,6 @@ static my_bool cli_read_query_result(MYSQL *mysql) ...@@ -2484,7 +2485,6 @@ static my_bool cli_read_query_result(MYSQL *mysql)
DBUG_RETURN(1); DBUG_RETURN(1);
mysql->status= MYSQL_STATUS_GET_RESULT; mysql->status= MYSQL_STATUS_GET_RESULT;
mysql->field_count= (uint) field_count; mysql->field_count= (uint) field_count;
mysql->warning_count= 0;
DBUG_PRINT("exit",("ok")); DBUG_PRINT("exit",("ok"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -1199,6 +1199,12 @@ struct Sroutine_hash_entry ...@@ -1199,6 +1199,12 @@ struct Sroutine_hash_entry
for LEX::sroutine/sroutine_list and sp_head::m_sroutines. for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
*/ */
Sroutine_hash_entry *next; Sroutine_hash_entry *next;
/*
Uppermost view which directly or indirectly uses this routine.
0 if routine is not used in view. Note that it also can be 0 if
statement uses routine both via view and directly.
*/
TABLE_LIST *belong_to_view;
}; };
...@@ -1253,9 +1259,11 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, ...@@ -1253,9 +1259,11 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
SYNOPSIS SYNOPSIS
add_used_routine() add_used_routine()
lex - LEX representing statement lex LEX representing statement
arena - arena in which memory for new element will be allocated arena Arena in which memory for new element will be allocated
key - key for the hash representing set key Key for the hash representing set
belong_to_view Uppermost view which uses this routine
(0 if routine is not used by view)
NOTES NOTES
Will also add element to end of 'LEX::sroutines_list' list. Will also add element to end of 'LEX::sroutines_list' list.
...@@ -1278,7 +1286,8 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, ...@@ -1278,7 +1286,8 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
*/ */
static bool add_used_routine(LEX *lex, Query_arena *arena, static bool add_used_routine(LEX *lex, Query_arena *arena,
const LEX_STRING *key) const LEX_STRING *key,
TABLE_LIST *belong_to_view)
{ {
if (!hash_search(&lex->sroutines, (byte *)key->str, key->length)) if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
{ {
...@@ -1292,6 +1301,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1292,6 +1301,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
memcpy(rn->key.str, key->str, key->length); memcpy(rn->key.str, key->str, key->length);
my_hash_insert(&lex->sroutines, (byte *)rn); my_hash_insert(&lex->sroutines, (byte *)rn);
lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next); lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
rn->belong_to_view= belong_to_view;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
...@@ -1322,7 +1332,7 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1322,7 +1332,7 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
sp_name *rt, char rt_type) sp_name *rt, char rt_type)
{ {
rt->set_routine_type(rt_type); rt->set_routine_type(rt_type);
(void)add_used_routine(lex, arena, &rt->m_sroutines_key); (void)add_used_routine(lex, arena, &rt->m_sroutines_key, 0);
lex->sroutines_list_own_last= lex->sroutines_list.next; lex->sroutines_list_own_last= lex->sroutines_list.next;
lex->sroutines_list_own_elements= lex->sroutines_list.elements; lex->sroutines_list_own_elements= lex->sroutines_list.elements;
} }
...@@ -1392,20 +1402,23 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src) ...@@ -1392,20 +1402,23 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src)
SYNOPSIS SYNOPSIS
sp_update_stmt_used_routines() sp_update_stmt_used_routines()
thd - thread context thd Thread context
lex - LEX representing statement lex LEX representing statement
src - hash representing set from which routines will be added src Hash representing set from which routines will be added
belong_to_view Uppermost view which uses these routines, 0 if none
NOTE NOTE
It will also add elements to end of 'LEX::sroutines_list' list. It will also add elements to end of 'LEX::sroutines_list' list.
*/ */
static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src) static void
sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
TABLE_LIST *belong_to_view)
{ {
for (uint i=0 ; i < src->records ; i++) for (uint i=0 ; i < src->records ; i++)
{ {
Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
(void)add_used_routine(lex, thd->stmt_arena, &rt->key); (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
} }
} }
...@@ -1416,19 +1429,21 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src) ...@@ -1416,19 +1429,21 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
SYNOPSIS SYNOPSIS
sp_update_stmt_used_routines() sp_update_stmt_used_routines()
thd Thread context thd Thread context
lex LEX representing statement lex LEX representing statement
src List representing set from which routines will be added src List representing set from which routines will be added
belong_to_view Uppermost view which uses these routines, 0 if none
NOTE NOTE
It will also add elements to end of 'LEX::sroutines_list' list. It will also add elements to end of 'LEX::sroutines_list' list.
*/ */
static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src) static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src,
TABLE_LIST *belong_to_view)
{ {
for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first; for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first;
rt; rt= rt->next) rt; rt= rt->next)
(void)add_used_routine(lex, thd->stmt_arena, &rt->key); (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
} }
...@@ -1533,9 +1548,11 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, ...@@ -1533,9 +1548,11 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
{ {
if (!(first && first_no_prelock)) if (!(first && first_no_prelock))
{ {
sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines); sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines,
rt->belong_to_view);
tabschnd|= tabschnd|=
sp->add_used_tables_to_table_list(thd, &lex->query_tables_last); sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
rt->belong_to_view);
} }
} }
first= FALSE; first= FALSE;
...@@ -1581,21 +1598,22 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock, ...@@ -1581,21 +1598,22 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock,
SYNOPSIS SYNOPSIS
sp_cache_routines_and_add_tables_for_view() sp_cache_routines_and_add_tables_for_view()
thd - thread context thd Thread context
lex - LEX representing statement lex LEX representing statement
aux_lex - LEX representing view view Table list element representing view
RETURN VALUE RETURN VALUE
0 - success 0 - success
non-0 - failure non-0 - failure
*/ */
int int
sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view)
{ {
Sroutine_hash_entry **last_cached_routine_ptr= Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next; (Sroutine_hash_entry **)lex->sroutines_list.next;
sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list); sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list,
view->top_table());
return sp_cache_routines_and_add_tables_aux(thd, lex, return sp_cache_routines_and_add_tables_aux(thd, lex,
*last_cached_routine_ptr, FALSE, *last_cached_routine_ptr, FALSE,
NULL); NULL);
...@@ -1609,9 +1627,9 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) ...@@ -1609,9 +1627,9 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
SYNOPSIS SYNOPSIS
sp_cache_routines_and_add_tables_for_triggers() sp_cache_routines_and_add_tables_for_triggers()
thd - thread context thd thread context
lex - LEX respresenting statement lex LEX respresenting statement
triggers - triggers of the table table Table list element for table with trigger
RETURN VALUE RETURN VALUE
0 - success 0 - success
...@@ -1620,11 +1638,12 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) ...@@ -1620,11 +1638,12 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
int int
sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
Table_triggers_list *triggers) TABLE_LIST *table)
{ {
int ret= 0; int ret= 0;
Table_triggers_list *triggers= table->table->triggers;
if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key)) if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key,
table->belong_to_view))
{ {
Sroutine_hash_entry **last_cached_routine_ptr= Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next; (Sroutine_hash_entry **)lex->sroutines_list.next;
...@@ -1634,10 +1653,12 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, ...@@ -1634,10 +1653,12 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{ {
if (triggers->bodies[i][j]) if (triggers->bodies[i][j])
{ {
(void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd, (void)triggers->bodies[i][j]->
&lex->query_tables_last); add_used_tables_to_table_list(thd, &lex->query_tables_last,
table->belong_to_view);
sp_update_stmt_used_routines(thd, lex, sp_update_stmt_used_routines(thd, lex,
&triggers->bodies[i][j]->m_sroutines); &triggers->bodies[i][j]->m_sroutines,
table->belong_to_view);
} }
} }
} }
......
...@@ -84,12 +84,13 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, ...@@ -84,12 +84,13 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
sp_name *rt, char rt_type); sp_name *rt, char rt_type);
void sp_remove_not_own_routines(LEX *lex); void sp_remove_not_own_routines(LEX *lex);
void sp_update_sp_used_routines(HASH *dst, HASH *src); void sp_update_sp_used_routines(HASH *dst, HASH *src);
int sp_cache_routines_and_add_tables(THD *thd, LEX *lex, int sp_cache_routines_and_add_tables(THD *thd, LEX *lex,
bool first_no_prelock, bool *tabs_changed); bool first_no_prelock,
bool *tabs_changed);
int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
LEX *aux_lex); TABLE_LIST *view);
int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
Table_triggers_list *triggers); TABLE_LIST *table);
extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first); extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
......
...@@ -3238,10 +3238,12 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) ...@@ -3238,10 +3238,12 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
SYNOPSIS SYNOPSIS
add_used_tables_to_table_list() add_used_tables_to_table_list()
thd - thread context thd [in] Thread context
query_tables_last_ptr - (in/out) pointer the next_global member of last query_tables_last_ptr [in/out] Pointer to the next_global member of
element of the list where tables will be added last element of the list where tables
(or to its root). will be added (or to its root).
belong_to_view [in] Uppermost view which uses this routine,
0 if none.
DESCRIPTION DESCRIPTION
Converts multi-set of tables used by this routine to table list and adds Converts multi-set of tables used by this routine to table list and adds
...@@ -3256,7 +3258,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) ...@@ -3256,7 +3258,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
bool bool
sp_head::add_used_tables_to_table_list(THD *thd, sp_head::add_used_tables_to_table_list(THD *thd,
TABLE_LIST ***query_tables_last_ptr) TABLE_LIST ***query_tables_last_ptr,
TABLE_LIST *belong_to_view)
{ {
uint i; uint i;
Query_arena *arena, backup; Query_arena *arena, backup;
...@@ -3299,6 +3302,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, ...@@ -3299,6 +3302,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->lock_type= stab->lock_type; table->lock_type= stab->lock_type;
table->cacheable_table= 1; table->cacheable_table= 1;
table->prelocking_placeholder= 1; table->prelocking_placeholder= 1;
table->belong_to_view= belong_to_view;
/* Everyting else should be zeroed */ /* Everyting else should be zeroed */
......
...@@ -310,7 +310,8 @@ class sp_head :private Query_arena ...@@ -310,7 +310,8 @@ class sp_head :private Query_arena
/* Add tables used by routine to the table list. */ /* Add tables used by routine to the table list. */
bool add_used_tables_to_table_list(THD *thd, bool add_used_tables_to_table_list(THD *thd,
TABLE_LIST ***query_tables_last_ptr); TABLE_LIST ***query_tables_last_ptr,
TABLE_LIST *belong_to_view);
/* /*
Check if this stored routine contains statements disallowed Check if this stored routine contains statements disallowed
......
...@@ -2128,7 +2128,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2128,7 +2128,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
if (!query_tables_last_own) if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last; query_tables_last_own= thd->lex->query_tables_last;
if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex, if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
tables->table->triggers)) tables))
{ {
/* /*
Serious error during reading stored routines from mysql.proc table. Serious error during reading stored routines from mysql.proc table.
...@@ -2158,8 +2158,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2158,8 +2158,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
/* We have at least one table in TL here. */ /* We have at least one table in TL here. */
if (!query_tables_last_own) if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last; query_tables_last_own= thd->lex->query_tables_last;
if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables))
tables->view))
{ {
/* /*
Serious error during reading stored routines from mysql.proc table. Serious error during reading stored routines from mysql.proc table.
......
...@@ -118,7 +118,7 @@ class Table_triggers_list: public Sql_alloc ...@@ -118,7 +118,7 @@ class Table_triggers_list: public Sql_alloc
friend class Item_trigger_field; friend class Item_trigger_field;
friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
Table_triggers_list *triggers); TABLE_LIST *table);
private: private:
bool prepare_record1_accessors(TABLE *table); bool prepare_record1_accessors(TABLE *table);
......
...@@ -14590,6 +14590,40 @@ static void test_bug14845() ...@@ -14590,6 +14590,40 @@ static void test_bug14845()
myquery(rc); myquery(rc);
} }
/*
Bug #15510: mysql_warning_count returns 0 after mysql_stmt_fetch which
should warn
*/
static void test_bug15510()
{
MYSQL_STMT *stmt;
MYSQL_RES *res;
int rc;
const char *query= "select 1 from dual where 1/0";
myheader("test_bug15510");
rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
myquery(rc);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, query, strlen(query));
check_execute(stmt, rc);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(mysql_warning_count(mysql));
/* Cleanup */
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "set @@sql_mode=''");
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -14849,6 +14883,7 @@ static struct my_tests_st my_tests[]= { ...@@ -14849,6 +14883,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug13488", test_bug13488 }, { "test_bug13488", test_bug13488 },
{ "test_bug13524", test_bug13524 }, { "test_bug13524", test_bug13524 },
{ "test_bug14845", test_bug14845 }, { "test_bug14845", test_bug14845 },
{ "test_bug15510", test_bug15510},
{ 0, 0 } { 0, 0 }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment