diff options
author | unknown <kostja@bodhi.(none)> | 2007-07-05 11:34:04 +0400 |
---|---|---|
committer | unknown <kostja@bodhi.(none)> | 2007-07-05 11:34:04 +0400 |
commit | e8966deecc0eda77c5b94c6f0004cc2159dbd158 (patch) | |
tree | 8d7427787cd278a6b8772c821b5c2aa97df51b03 | |
parent | b1ec3b534d530807995955c1c249496b0912a906 (diff) | |
download | mariadb-git-e8966deecc0eda77c5b94c6f0004cc2159dbd158.tar.gz |
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.
-rw-r--r-- | mysql-test/r/sp.result | 18 | ||||
-rw-r--r-- | mysql-test/r/trigger.result | 4 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 25 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 37 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 15 |
8 files changed, 93 insertions, 14 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 5d7371b0991..7a4deb3ea5f 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -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 diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 5405a632aa4..290929d476d 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -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); diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index cfc97fab777..54dc84ad19d 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -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 diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 7158d02956e..0fa92f33de2 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -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; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index cbfba3d4d80..aefa3d43b14 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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 diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f8405ef14ca..3f55b3baae1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b65ad705a36..124fcff9517 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6c146f77ed6..949f3ed4161 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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; |