mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
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. mysql-test/r/sp.result: Update test results (Bug#29050) mysql-test/r/trigger.result: Update results. mysql-test/t/sp.test: Add a test case for Bug#29050 mysql-test/t/trigger.test: Fix wrong behavior covered with tests. sql/sql_lex.cc: Implement st_lex::copy_db_to(). sql/sql_lex.h: Declare st_lex::copy_db_to(). sql/sql_parse.cc: Use st_lex::copy_db_to() in add_table_to_list, rather than THD::copy_db_to(). The former will use the database of the sphead, if we're parsing a stored routine, not the default database in THD. The default database is needed to initialize tables->db when the database part was not explicitly specified in the identifier. sql/sql_yacc.yy: Use st_lex::copy_db_to() in the parser, rather than THD::copy_db_to(). The former will use the database of the sphead, if we're parsing a stored routine, not the default database in THD.
This commit is contained in:
parent
b1ec3b534d
commit
e8966deecc
8 changed files with 93 additions and 14 deletions
|
@ -6183,4 +6183,22 @@ call mysqltest_db1.sp_bug28551();
|
|||
show warnings;
|
||||
Level Code Message
|
||||
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
|
||||
|
|
|
@ -351,7 +351,7 @@ create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
|
|||
ERROR HY000: Trigger in wrong schema
|
||||
use mysqltest;
|
||||
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;
|
||||
use test;
|
||||
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;
|
||||
ERROR 3D000: No database selected
|
||||
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;
|
||||
ERROR 3D000: No database selected
|
||||
create table t1 (id int);
|
||||
|
|
|
@ -7142,5 +7142,30 @@ create procedure mysqltest_db1.sp_bug28551() begin end;
|
|||
call mysqltest_db1.sp_bug28551();
|
||||
show warnings;
|
||||
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
|
||||
|
|
|
@ -406,7 +406,7 @@ create table mysqltest.t1 (i int);
|
|||
--error ER_TRG_IN_WRONG_SCHEMA
|
||||
create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
|
||||
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;
|
||||
drop database mysqltest;
|
||||
use test;
|
||||
|
@ -1040,7 +1040,7 @@ drop table t1;
|
|||
connection addconwithoutdb;
|
||||
--error ER_NO_DB_ERROR
|
||||
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;
|
||||
--error ER_NO_DB_ERROR
|
||||
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
|
||||
|
||||
|
|
|
@ -1237,6 +1237,8 @@ typedef struct st_lex : public Query_tables_list
|
|||
context_stack.pop();
|
||||
}
|
||||
|
||||
bool copy_db_to(char **p_db, uint *p_db_length) const;
|
||||
|
||||
Name_resolution_context *current_context()
|
||||
{
|
||||
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_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);
|
||||
|
||||
ptr->alias= alias_str;
|
||||
|
|
|
@ -1565,14 +1565,14 @@ sp_name:
|
|||
}
|
||||
| ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= Lex;
|
||||
LEX_STRING db;
|
||||
if (check_routine_name($1))
|
||||
{
|
||||
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
if (thd->copy_db_to(&db.str, &db.length))
|
||||
if (lex->copy_db_to(&db.str, &db.length))
|
||||
MYSQL_YYABORT;
|
||||
$$= new sp_name(db, $1, false);
|
||||
if ($$)
|
||||
|
@ -3624,10 +3624,9 @@ alter:
|
|||
opt_create_database_options
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
THD *thd= Lex->thd;
|
||||
lex->sql_command=SQLCOM_ALTER_DB;
|
||||
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;
|
||||
}
|
||||
| ALTER PROCEDURE sp_name
|
||||
|
@ -3795,10 +3794,9 @@ alter_list_item:
|
|||
| RENAME opt_to table_ident
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
THD *thd= lex->thd;
|
||||
lex->select_lex.db=$3->db.str;
|
||||
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;
|
||||
}
|
||||
|
@ -5148,7 +5146,7 @@ simple_expr:
|
|||
{
|
||||
THD *thd= lex->thd;
|
||||
LEX_STRING db;
|
||||
if (thd->copy_db_to(&db.str, &db.length))
|
||||
if (lex->copy_db_to(&db.str, &db.length))
|
||||
MYSQL_YYABORT;
|
||||
sp_name *name= new sp_name(db, $1, false);
|
||||
if (name)
|
||||
|
@ -9025,8 +9023,7 @@ grant_ident:
|
|||
'*'
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
THD *thd= lex->thd;
|
||||
if (thd->copy_db_to(&lex->current_select->db, NULL))
|
||||
if (lex->copy_db_to(&lex->current_select->db, NULL))
|
||||
MYSQL_YYABORT;
|
||||
if (lex->grant == GLOBAL_ACLS)
|
||||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||||
|
|
Loading…
Add table
Reference in a new issue