mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Avoid spurious error when restoring INFORMATION_SCHEMA as the current
database after failing to execute a stored procedure in an inaccessible database. (Bug #12318)
This commit is contained in:
@ -236,3 +236,16 @@ drop procedure bug7291_2;
|
|||||||
drop procedure bug7291_0;
|
drop procedure bug7291_0;
|
||||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
|
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
|
||||||
drop user user1@localhost;
|
drop user user1@localhost;
|
||||||
|
drop database if exists mysqltest_1;
|
||||||
|
create database mysqltest_1;
|
||||||
|
create procedure mysqltest_1.p1()
|
||||||
|
begin
|
||||||
|
select 1 from dual;
|
||||||
|
end//
|
||||||
|
grant usage on *.* to mysqltest_1@localhost;
|
||||||
|
call mysqltest_1.p1();
|
||||||
|
ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1'
|
||||||
|
drop procedure mysqltest_1.p1;
|
||||||
|
drop database mysqltest_1;
|
||||||
|
revoke usage on *.* from mysqltest_1@localhost;
|
||||||
|
drop user mysqltest_1@localhost;
|
||||||
|
@ -371,3 +371,39 @@ drop procedure bug7291_0;
|
|||||||
disconnect user1;
|
disconnect user1;
|
||||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
|
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
|
||||||
drop user user1@localhost;
|
drop user user1@localhost;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #12318: Wrong error message when accessing an inaccessible stored
|
||||||
|
# procedure in another database when the current database is
|
||||||
|
# information_schema.
|
||||||
|
#
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists mysqltest_1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
create database mysqltest_1;
|
||||||
|
delimiter //;
|
||||||
|
create procedure mysqltest_1.p1()
|
||||||
|
begin
|
||||||
|
select 1 from dual;
|
||||||
|
end//
|
||||||
|
delimiter ;//
|
||||||
|
|
||||||
|
grant usage on *.* to mysqltest_1@localhost;
|
||||||
|
|
||||||
|
connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK);
|
||||||
|
connection n1;
|
||||||
|
--error 1370
|
||||||
|
call mysqltest_1.p1();
|
||||||
|
disconnect n1;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
drop procedure mysqltest_1.p1;
|
||||||
|
drop database mysqltest_1;
|
||||||
|
|
||||||
|
revoke usage on *.* from mysqltest_1@localhost;
|
||||||
|
drop user mysqltest_1@localhost;
|
||||||
|
|
||||||
|
# End of 5.0 bugs.
|
||||||
|
@ -587,7 +587,7 @@ int quick_rm_table(enum db_type base,const char *db,
|
|||||||
const char *table_name);
|
const char *table_name);
|
||||||
void close_cached_table(THD *thd, TABLE *table);
|
void close_cached_table(THD *thd, TABLE *table);
|
||||||
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
|
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
|
||||||
bool mysql_change_db(THD *thd,const char *name);
|
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
|
||||||
void mysql_parse(THD *thd,char *inBuf,uint length);
|
void mysql_parse(THD *thd,char *inBuf,uint length);
|
||||||
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
|
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
|
||||||
bool is_update_query(enum enum_sql_command command);
|
bool is_update_query(enum enum_sql_command command);
|
||||||
|
110
sql/sp.cc
110
sql/sp.cc
@ -427,7 +427,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
LEX *newlex= thd->lex;
|
LEX *newlex= thd->lex;
|
||||||
sp_head *sp= newlex->sphead;
|
sp_head *sp= newlex->sphead;
|
||||||
|
|
||||||
if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
|
if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
|
||||||
goto done;
|
goto done;
|
||||||
if (sp)
|
if (sp)
|
||||||
{
|
{
|
||||||
@ -438,7 +438,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
|
if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
|
||||||
goto done;
|
goto done;
|
||||||
*sphp= thd->lex->sphead;
|
*sphp= thd->lex->sphead;
|
||||||
(*sphp)->set_info((char *)definer, (uint)strlen(definer),
|
(*sphp)->set_info((char *)definer, (uint)strlen(definer),
|
||||||
@ -594,7 +594,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
done:
|
done:
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
if (dbchanged)
|
if (dbchanged)
|
||||||
(void)sp_change_db(thd, olddb, 1);
|
(void)mysql_change_db(thd, olddb, 1);
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1612,112 +1612,10 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int ret= sp_change_db(thd, newdb, no_access_check);
|
int ret= mysql_change_db(thd, newdb, no_access_check);
|
||||||
|
|
||||||
if (! ret)
|
if (! ret)
|
||||||
*dbchangedp= TRUE;
|
*dbchangedp= TRUE;
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Change database.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
sp_change_db()
|
|
||||||
thd Thread handler
|
|
||||||
name Database name
|
|
||||||
empty_is_ok True= it's ok with "" as name
|
|
||||||
no_access_check True= don't do access check
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
This is the same as mysql_change_db(), but with some extra
|
|
||||||
arguments for Stored Procedure usage; doing implicit "use"
|
|
||||||
when executing an SP in a different database.
|
|
||||||
We also use different error routines, since this might be
|
|
||||||
invoked from a function when executing a query or statement.
|
|
||||||
Note: We would have prefered to reuse mysql_change_db(), but
|
|
||||||
the error handling in particular made that too awkward, so
|
|
||||||
we (reluctantly) have a "copy" here.
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
0 ok
|
|
||||||
1 error
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
sp_change_db(THD *thd, char *name, bool no_access_check)
|
|
||||||
{
|
|
||||||
int length, db_length;
|
|
||||||
char *dbname=my_strdup((char*) name,MYF(MY_WME));
|
|
||||||
char path[FN_REFLEN];
|
|
||||||
HA_CREATE_INFO create;
|
|
||||||
DBUG_ENTER("sp_change_db");
|
|
||||||
DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
|
|
||||||
|
|
||||||
db_length= (!dbname ? 0 : strip_sp(dbname));
|
|
||||||
if (dbname && db_length)
|
|
||||||
{
|
|
||||||
if ((db_length > NAME_LEN) || check_db_name(dbname))
|
|
||||||
{
|
|
||||||
my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
|
|
||||||
x_free(dbname);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dbname && db_length)
|
|
||||||
{
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
if (! no_access_check)
|
|
||||||
{
|
|
||||||
ulong db_access;
|
|
||||||
|
|
||||||
if (test_all_bits(thd->master_access,DB_ACLS))
|
|
||||||
db_access=DB_ACLS;
|
|
||||||
else
|
|
||||||
db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
|
|
||||||
thd->master_access);
|
|
||||||
if (!(db_access & DB_ACLS) &&
|
|
||||||
(!grant_option || check_grant_db(thd,dbname)))
|
|
||||||
{
|
|
||||||
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
|
|
||||||
thd->priv_user,
|
|
||||||
thd->priv_host,
|
|
||||||
dbname);
|
|
||||||
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
|
|
||||||
thd->priv_user,
|
|
||||||
thd->priv_host,
|
|
||||||
dbname);
|
|
||||||
my_free(dbname,MYF(0));
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
(void) sprintf(path,"%s/%s",mysql_data_home,dbname);
|
|
||||||
length=unpack_dirname(path,path); // Convert if not unix
|
|
||||||
if (length && path[length-1] == FN_LIBCHAR)
|
|
||||||
path[length-1]=0; // remove ending '\'
|
|
||||||
if (access(path,F_OK))
|
|
||||||
{
|
|
||||||
my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
|
|
||||||
my_free(dbname,MYF(0));
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x_free(thd->db);
|
|
||||||
thd->db=dbname; // THD::~THD will free this
|
|
||||||
thd->db_length=db_length;
|
|
||||||
|
|
||||||
if (dbname && db_length)
|
|
||||||
{
|
|
||||||
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
|
|
||||||
load_db_opt(thd, path, &create);
|
|
||||||
thd->db_charset= create.default_table_charset ?
|
|
||||||
create.default_table_charset :
|
|
||||||
thd->variables.collation_server;
|
|
||||||
thd->variables.collation_database= thd->db_charset;
|
|
||||||
}
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
4
sql/sp.h
4
sql/sp.h
@ -112,8 +112,4 @@ int
|
|||||||
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
|
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
|
||||||
bool no_access_check, bool *dbchangedp);
|
bool no_access_check, bool *dbchangedp);
|
||||||
|
|
||||||
// Like mysql_change_db() but handles empty db name and the send_ok() problem.
|
|
||||||
int
|
|
||||||
sp_change_db(THD *thd, char *db, bool no_access_check);
|
|
||||||
|
|
||||||
#endif /* _SP_H_ */
|
#endif /* _SP_H_ */
|
||||||
|
@ -996,8 +996,9 @@ err:
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
mysql_change_db()
|
mysql_change_db()
|
||||||
thd Thread handler
|
thd Thread handler
|
||||||
name Databasename
|
name Databasename
|
||||||
|
no_access_check True= don't do access check
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Becasue the database name may have been given directly from the
|
Becasue the database name may have been given directly from the
|
||||||
@ -1009,15 +1010,16 @@ err:
|
|||||||
replication slave SQL thread (for that thread, setting of thd->db is done
|
replication slave SQL thread (for that thread, setting of thd->db is done
|
||||||
in ::exec_event() methods of log_event.cc).
|
in ::exec_event() methods of log_event.cc).
|
||||||
|
|
||||||
This function does not send the error message to the client, if that
|
This function does not send anything, including error messages to the
|
||||||
should be sent to the client, call net_send_error after this function
|
client, if that should be sent to the client, call net_send_error after
|
||||||
|
this function.
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 ok
|
0 ok
|
||||||
1 error
|
1 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool mysql_change_db(THD *thd, const char *name)
|
bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
|
||||||
{
|
{
|
||||||
int length, db_length;
|
int length, db_length;
|
||||||
char *dbname=my_strdup((char*) name,MYF(MY_WME));
|
char *dbname=my_strdup((char*) name,MYF(MY_WME));
|
||||||
@ -1053,23 +1055,25 @@ bool mysql_change_db(THD *thd, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (test_all_bits(thd->master_access,DB_ACLS))
|
if (!no_access_check) {
|
||||||
db_access=DB_ACLS;
|
if (test_all_bits(thd->master_access,DB_ACLS))
|
||||||
else
|
db_access=DB_ACLS;
|
||||||
db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
|
else
|
||||||
thd->master_access);
|
db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
|
||||||
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
|
thd->master_access);
|
||||||
{
|
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
|
||||||
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
|
{
|
||||||
thd->priv_user,
|
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
|
||||||
thd->priv_host,
|
thd->priv_user,
|
||||||
dbname);
|
thd->priv_host,
|
||||||
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
|
dbname);
|
||||||
thd->priv_user,
|
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
|
||||||
thd->priv_host,
|
thd->priv_user,
|
||||||
dbname);
|
thd->priv_host,
|
||||||
my_free(dbname,MYF(0));
|
dbname);
|
||||||
DBUG_RETURN(1);
|
my_free(dbname,MYF(0));
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
(void) sprintf(path,"%s/%s",mysql_data_home,dbname);
|
(void) sprintf(path,"%s/%s",mysql_data_home,dbname);
|
||||||
@ -1083,12 +1087,12 @@ bool mysql_change_db(THD *thd, const char *name)
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
send_ok(thd);
|
|
||||||
x_free(thd->db);
|
x_free(thd->db);
|
||||||
thd->db=dbname; // THD::~THD will free this
|
thd->db=dbname; // THD::~THD will free this
|
||||||
thd->db_length=db_length;
|
thd->db_length=db_length;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
thd->db_access=db_access;
|
if (!no_access_check)
|
||||||
|
thd->db_access=db_access;
|
||||||
#endif
|
#endif
|
||||||
if (schema_db)
|
if (schema_db)
|
||||||
{
|
{
|
||||||
|
@ -275,7 +275,7 @@ int check_user(THD *thd, enum enum_server_command command,
|
|||||||
{
|
{
|
||||||
thd->db= 0;
|
thd->db= 0;
|
||||||
thd->db_length= 0;
|
thd->db_length= 0;
|
||||||
if (mysql_change_db(thd, db))
|
if (mysql_change_db(thd, db, FALSE))
|
||||||
{
|
{
|
||||||
/* Send the error to the client */
|
/* Send the error to the client */
|
||||||
net_send_error(thd);
|
net_send_error(thd);
|
||||||
@ -284,8 +284,7 @@ int check_user(THD *thd, enum enum_server_command command,
|
|||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
send_ok(thd);
|
||||||
send_ok(thd);
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -410,7 +409,7 @@ int check_user(THD *thd, enum enum_server_command command,
|
|||||||
/* Change database if necessary */
|
/* Change database if necessary */
|
||||||
if (db && db[0])
|
if (db && db[0])
|
||||||
{
|
{
|
||||||
if (mysql_change_db(thd, db))
|
if (mysql_change_db(thd, db, FALSE))
|
||||||
{
|
{
|
||||||
/* Send error to the client */
|
/* Send error to the client */
|
||||||
net_send_error(thd);
|
net_send_error(thd);
|
||||||
@ -419,8 +418,7 @@ int check_user(THD *thd, enum enum_server_command command,
|
|||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
send_ok(thd);
|
||||||
send_ok(thd);
|
|
||||||
thd->password= test(passwd_len); // remember for error messages
|
thd->password= test(passwd_len); // remember for error messages
|
||||||
/* Ready to handle queries */
|
/* Ready to handle queries */
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -1514,8 +1512,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||||||
&LOCK_status);
|
&LOCK_status);
|
||||||
thd->convert_string(&tmp, system_charset_info,
|
thd->convert_string(&tmp, system_charset_info,
|
||||||
packet, strlen(packet), thd->charset());
|
packet, strlen(packet), thd->charset());
|
||||||
if (!mysql_change_db(thd, tmp.str))
|
if (!mysql_change_db(thd, tmp.str, FALSE))
|
||||||
|
{
|
||||||
mysql_log.write(thd,command,"%s",thd->db);
|
mysql_log.write(thd,command,"%s",thd->db);
|
||||||
|
send_ok(thd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_REPLICATION
|
#ifdef HAVE_REPLICATION
|
||||||
@ -3407,7 +3408,8 @@ end_with_restore_list:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case SQLCOM_CHANGE_DB:
|
case SQLCOM_CHANGE_DB:
|
||||||
mysql_change_db(thd,select_lex->db);
|
if (!mysql_change_db(thd,select_lex->db,FALSE))
|
||||||
|
send_ok(thd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SQLCOM_LOAD:
|
case SQLCOM_LOAD:
|
||||||
|
Reference in New Issue
Block a user