A fix and a test case for Bug#29050 Creation of a legal stored procedure
fails if a database is not selected prior. The problem manifested itself when a user tried to create a routine that had non-fully-qualified identifiers in its bodies and there was no current database selected. This is a regression introduced by the fix for Bug 19022: The patch for Bug 19022 changes the code to always produce a warning if we can't resolve the current database in the parser. In this case this was not necessary, since even though the produced parsed tree was incorrect, we never re-use sphead that was obtained at first parsing of CREATE PROCEDURE. The sphead that is anyhow used is always obtained through db_load_routine, and there we change the current database to sphead->m_db before calling yyparse. The idea of the fix is to resolve the current database directly using lex->sphead->m_db member when parsing a stored routine body, when such is present. This patch removes the need to reset the current database when loading a trigger or routine definition into SP cache. The redundant code will be removed in 5.1.
This commit is contained in:
parent
c3f37e0b3d
commit
a7b05cb786
@ -6183,4 +6183,22 @@ call mysqltest_db1.sp_bug28551();
|
|||||||
show warnings;
|
show warnings;
|
||||||
Level Code Message
|
Level Code Message
|
||||||
drop database mysqltest_db1;
|
drop database mysqltest_db1;
|
||||||
|
drop database if exists mysqltest_db1;
|
||||||
|
drop table if exists test.t1;
|
||||||
|
create database mysqltest_db1;
|
||||||
|
use mysqltest_db1;
|
||||||
|
drop database mysqltest_db1;
|
||||||
|
create table test.t1 (id int);
|
||||||
|
insert into test.t1 (id) values (1);
|
||||||
|
create procedure test.sp_bug29050() begin select * from t1; end//
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
call test.sp_bug29050();
|
||||||
|
id
|
||||||
|
1
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
use test;
|
||||||
|
drop procedure sp_bug29050;
|
||||||
|
drop table t1;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
|
@ -351,7 +351,7 @@ create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
|
|||||||
ERROR HY000: Trigger in wrong schema
|
ERROR HY000: Trigger in wrong schema
|
||||||
use mysqltest;
|
use mysqltest;
|
||||||
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
|
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
|
||||||
ERROR HY000: Trigger in wrong schema
|
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||||
drop database mysqltest;
|
drop database mysqltest;
|
||||||
use test;
|
use test;
|
||||||
create table t1 (i int, j int default 10, k int not null, key (k));
|
create table t1 (i int, j int default 10, k int not null, key (k));
|
||||||
@ -842,7 +842,7 @@ drop table t1;
|
|||||||
create trigger t1_bi before insert on test.t1 for each row set @a:=0;
|
create trigger t1_bi before insert on test.t1 for each row set @a:=0;
|
||||||
ERROR 3D000: No database selected
|
ERROR 3D000: No database selected
|
||||||
create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
||||||
ERROR 3D000: No database selected
|
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||||
drop trigger t1_bi;
|
drop trigger t1_bi;
|
||||||
ERROR 3D000: No database selected
|
ERROR 3D000: No database selected
|
||||||
create table t1 (id int);
|
create table t1 (id int);
|
||||||
|
@ -7142,5 +7142,30 @@ create procedure mysqltest_db1.sp_bug28551() begin end;
|
|||||||
call mysqltest_db1.sp_bug28551();
|
call mysqltest_db1.sp_bug28551();
|
||||||
show warnings;
|
show warnings;
|
||||||
drop database mysqltest_db1;
|
drop database mysqltest_db1;
|
||||||
|
#
|
||||||
|
# Bug#29050 Creation of a legal stored procedure fails if a database is not
|
||||||
|
# selected prior
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists mysqltest_db1;
|
||||||
|
drop table if exists test.t1;
|
||||||
|
--enable_warnings
|
||||||
|
create database mysqltest_db1;
|
||||||
|
use mysqltest_db1;
|
||||||
|
# For the sake of its side effect
|
||||||
|
drop database mysqltest_db1;
|
||||||
|
# Now we have no current database selected.
|
||||||
|
create table test.t1 (id int);
|
||||||
|
insert into test.t1 (id) values (1);
|
||||||
|
delimiter //;
|
||||||
|
create procedure test.sp_bug29050() begin select * from t1; end//
|
||||||
|
delimiter ;//
|
||||||
|
show warnings;
|
||||||
|
call test.sp_bug29050();
|
||||||
|
show warnings;
|
||||||
|
# Restore the old current database
|
||||||
|
use test;
|
||||||
|
drop procedure sp_bug29050;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
@ -406,7 +406,7 @@ create table mysqltest.t1 (i int);
|
|||||||
--error ER_TRG_IN_WRONG_SCHEMA
|
--error ER_TRG_IN_WRONG_SCHEMA
|
||||||
create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
|
create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
|
||||||
use mysqltest;
|
use mysqltest;
|
||||||
--error ER_TRG_IN_WRONG_SCHEMA
|
--error ER_NO_SUCH_TABLE
|
||||||
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
|
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
|
||||||
drop database mysqltest;
|
drop database mysqltest;
|
||||||
use test;
|
use test;
|
||||||
@ -1040,7 +1040,7 @@ drop table t1;
|
|||||||
connection addconwithoutdb;
|
connection addconwithoutdb;
|
||||||
--error ER_NO_DB_ERROR
|
--error ER_NO_DB_ERROR
|
||||||
create trigger t1_bi before insert on test.t1 for each row set @a:=0;
|
create trigger t1_bi before insert on test.t1 for each row set @a:=0;
|
||||||
--error ER_NO_DB_ERROR
|
--error ER_NO_SUCH_TABLE
|
||||||
create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
create trigger test.t1_bi before insert on t1 for each row set @a:=0;
|
||||||
--error ER_NO_DB_ERROR
|
--error ER_NO_DB_ERROR
|
||||||
drop trigger t1_bi;
|
drop trigger t1_bi;
|
||||||
|
@ -1974,6 +1974,43 @@ uint8 st_lex::get_effective_with_check(st_table_list *view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
This method should be called only during parsing.
|
||||||
|
It is aware of compound statements (stored routine bodies)
|
||||||
|
and will initialize the destination with the default
|
||||||
|
database of the stored routine, rather than the default
|
||||||
|
database of the connection it is parsed in.
|
||||||
|
E.g. if one has no current database selected, or current database
|
||||||
|
set to 'bar' and then issues:
|
||||||
|
|
||||||
|
CREATE PROCEDURE foo.p1() BEGIN SELECT * FROM t1 END//
|
||||||
|
|
||||||
|
t1 is meant to refer to foo.t1, not to bar.t1.
|
||||||
|
|
||||||
|
This method is needed to support this rule.
|
||||||
|
|
||||||
|
@return TRUE in case of error (parsing should be aborted, FALSE in
|
||||||
|
case of success
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
st_lex::copy_db_to(char **p_db, uint *p_db_length) const
|
||||||
|
{
|
||||||
|
if (sphead)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(sphead->m_db.str && sphead->m_db.length);
|
||||||
|
/*
|
||||||
|
It is safe to assign the string by-pointer, both sphead and
|
||||||
|
its statements reside in the same memory root.
|
||||||
|
*/
|
||||||
|
*p_db= sphead->m_db.str;
|
||||||
|
if (p_db_length)
|
||||||
|
*p_db_length= sphead->m_db.length;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return thd->copy_db_to(p_db, p_db_length);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
initialize limit counters
|
initialize limit counters
|
||||||
|
|
||||||
|
@ -1237,6 +1237,8 @@ typedef struct st_lex : public Query_tables_list
|
|||||||
context_stack.pop();
|
context_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool copy_db_to(char **p_db, uint *p_db_length) const;
|
||||||
|
|
||||||
Name_resolution_context *current_context()
|
Name_resolution_context *current_context()
|
||||||
{
|
{
|
||||||
return context_stack.head();
|
return context_stack.head();
|
||||||
|
@ -6397,7 +6397,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
|||||||
ptr->db= table->db.str;
|
ptr->db= table->db.str;
|
||||||
ptr->db_length= table->db.length;
|
ptr->db_length= table->db.length;
|
||||||
}
|
}
|
||||||
else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
|
else if (lex->copy_db_to(&ptr->db, &ptr->db_length))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
ptr->alias= alias_str;
|
ptr->alias= alias_str;
|
||||||
|
@ -1565,14 +1565,14 @@ sp_name:
|
|||||||
}
|
}
|
||||||
| ident
|
| ident
|
||||||
{
|
{
|
||||||
THD *thd= YYTHD;
|
LEX *lex= Lex;
|
||||||
LEX_STRING db;
|
LEX_STRING db;
|
||||||
if (check_routine_name($1))
|
if (check_routine_name($1))
|
||||||
{
|
{
|
||||||
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
|
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
if (thd->copy_db_to(&db.str, &db.length))
|
if (lex->copy_db_to(&db.str, &db.length))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
$$= new sp_name(db, $1, false);
|
$$= new sp_name(db, $1, false);
|
||||||
if ($$)
|
if ($$)
|
||||||
@ -3624,10 +3624,9 @@ alter:
|
|||||||
opt_create_database_options
|
opt_create_database_options
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
THD *thd= Lex->thd;
|
|
||||||
lex->sql_command=SQLCOM_ALTER_DB;
|
lex->sql_command=SQLCOM_ALTER_DB;
|
||||||
lex->name= $3;
|
lex->name= $3;
|
||||||
if (lex->name == NULL && thd->copy_db_to(&lex->name, NULL))
|
if (lex->name == NULL && lex->copy_db_to(&lex->name, NULL))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| ALTER PROCEDURE sp_name
|
| ALTER PROCEDURE sp_name
|
||||||
@ -3795,10 +3794,9 @@ alter_list_item:
|
|||||||
| RENAME opt_to table_ident
|
| RENAME opt_to table_ident
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
THD *thd= lex->thd;
|
|
||||||
lex->select_lex.db=$3->db.str;
|
lex->select_lex.db=$3->db.str;
|
||||||
if (lex->select_lex.db == NULL &&
|
if (lex->select_lex.db == NULL &&
|
||||||
thd->copy_db_to(&lex->select_lex.db, NULL))
|
lex->copy_db_to(&lex->select_lex.db, NULL))
|
||||||
{
|
{
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
@ -5148,7 +5146,7 @@ simple_expr:
|
|||||||
{
|
{
|
||||||
THD *thd= lex->thd;
|
THD *thd= lex->thd;
|
||||||
LEX_STRING db;
|
LEX_STRING db;
|
||||||
if (thd->copy_db_to(&db.str, &db.length))
|
if (lex->copy_db_to(&db.str, &db.length))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
sp_name *name= new sp_name(db, $1, false);
|
sp_name *name= new sp_name(db, $1, false);
|
||||||
if (name)
|
if (name)
|
||||||
@ -9025,8 +9023,7 @@ grant_ident:
|
|||||||
'*'
|
'*'
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
THD *thd= lex->thd;
|
if (lex->copy_db_to(&lex->current_select->db, NULL))
|
||||||
if (thd->copy_db_to(&lex->current_select->db, NULL))
|
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
if (lex->grant == GLOBAL_ACLS)
|
if (lex->grant == GLOBAL_ACLS)
|
||||||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user