mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
WL#1366: Use the schema (db) associated with an SP.
Phase 3: Made qualified names work for functions as well. mysql-test/r/sp-security.result: New testcases for functions with qualified names. mysql-test/t/sp-security.test: New testcases for functions with qualified names. sql/item_func.cc: Added error handling for stored function, if it doesn't exist. sql/item_func.h: Set null_value if execution of a stored function fails. sql/mysql_priv.h: Reverted previous change: No optional args for mysql_change_db(). (SPs use a specially tailored function instead.) sql/sp.cc: Copied mysql_change_db() from sql_db.cc and modified specially for SPs. sql/sp_head.cc: Fixed error handling for errors in functions during query/statement execution. sql/sql_db.cc: Reverted previous change: No optional args for mysql_change_db(). (SPs use a specially tailored function instead.) sql/sql_yacc.yy: Reworked the stored function/UDF invokation parsing and added qualified names for stored functions. UDFs now have precedence over stored functions (whith unqualified name). When using an unqualified name, only IDENT_sys is allowed (i.e. no unreserved keywords), since we get unresolvable reduce/reduce conflicts otherwise.
This commit is contained in:
@ -10,14 +10,27 @@ insert into db1_secret.t1 values (user(), i);
|
|||||||
show procedure status like 'stamp';
|
show procedure status like 'stamp';
|
||||||
Db Name Type Definer Modified Created Security_type Comment
|
Db Name Type Definer Modified Created Security_type Comment
|
||||||
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
|
create function db() returns varchar(64) return database();
|
||||||
|
show function status like 'db';
|
||||||
|
Db Name Type Definer Modified Created Security_type Comment
|
||||||
|
db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
call stamp(1);
|
call stamp(1);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
u i
|
u i
|
||||||
root@localhost 1
|
root@localhost 1
|
||||||
|
select db();
|
||||||
|
db()
|
||||||
|
db1_secret
|
||||||
call db1_secret.stamp(2);
|
call db1_secret.stamp(2);
|
||||||
|
select db1_secret.db();
|
||||||
|
db1_secret.db()
|
||||||
|
db1_secret
|
||||||
select * from db1_secret.t1;
|
select * from db1_secret.t1;
|
||||||
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
|
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
|
||||||
call db1_secret.stamp(3);
|
call db1_secret.stamp(3);
|
||||||
|
select db1_secret.db();
|
||||||
|
db1_secret.db()
|
||||||
|
db1_secret
|
||||||
select * from db1_secret.t1;
|
select * from db1_secret.t1;
|
||||||
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
||||||
select * from t1;
|
select * from t1;
|
||||||
@ -29,6 +42,10 @@ alter procedure stamp sql security invoker;
|
|||||||
show procedure status like 'stamp';
|
show procedure status like 'stamp';
|
||||||
Db Name Type Definer Modified Created Security_type Comment
|
Db Name Type Definer Modified Created Security_type Comment
|
||||||
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
|
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
|
||||||
|
alter function db sql security invoker;
|
||||||
|
show function status like 'db';
|
||||||
|
Db Name Type Definer Modified Created Security_type Comment
|
||||||
|
db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
|
||||||
call stamp(4);
|
call stamp(4);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
u i
|
u i
|
||||||
@ -36,10 +53,17 @@ root@localhost 1
|
|||||||
user1@localhost 2
|
user1@localhost 2
|
||||||
anon@localhost 3
|
anon@localhost 3
|
||||||
root@localhost 4
|
root@localhost 4
|
||||||
|
select db();
|
||||||
|
db()
|
||||||
|
db1_secret
|
||||||
call db1_secret.stamp(5);
|
call db1_secret.stamp(5);
|
||||||
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
|
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
|
||||||
|
select db1_secret.db();
|
||||||
|
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
|
||||||
call db1_secret.stamp(6);
|
call db1_secret.stamp(6);
|
||||||
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
||||||
|
select db1_secret.db();
|
||||||
|
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
||||||
drop database if exists db2;
|
drop database if exists db2;
|
||||||
create database db2;
|
create database db2;
|
||||||
use db2;
|
use db2;
|
||||||
@ -74,6 +98,7 @@ s1
|
|||||||
2
|
2
|
||||||
2
|
2
|
||||||
drop procedure db1_secret.stamp;
|
drop procedure db1_secret.stamp;
|
||||||
|
drop function db1_secret.db;
|
||||||
drop procedure db2.p;
|
drop procedure db2.p;
|
||||||
drop procedure db2.q;
|
drop procedure db2.q;
|
||||||
use test;
|
use test;
|
||||||
|
@ -21,15 +21,20 @@ use db1_secret;
|
|||||||
|
|
||||||
create table t1 ( u varchar(64), i int );
|
create table t1 ( u varchar(64), i int );
|
||||||
|
|
||||||
# Our test procedure
|
# A test procedure and function
|
||||||
create procedure stamp(i int)
|
create procedure stamp(i int)
|
||||||
insert into db1_secret.t1 values (user(), i);
|
insert into db1_secret.t1 values (user(), i);
|
||||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||||
show procedure status like 'stamp';
|
show procedure status like 'stamp';
|
||||||
|
|
||||||
|
create function db() returns varchar(64) return database();
|
||||||
|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||||
|
show function status like 'db';
|
||||||
|
|
||||||
# root can, of course
|
# root can, of course
|
||||||
call stamp(1);
|
call stamp(1);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
select db();
|
||||||
|
|
||||||
connect (con2user1,localhost,user1,,);
|
connect (con2user1,localhost,user1,,);
|
||||||
connect (con3anon,localhost,anon,,);
|
connect (con3anon,localhost,anon,,);
|
||||||
@ -41,6 +46,7 @@ connection con2user1;
|
|||||||
|
|
||||||
# This should work...
|
# This should work...
|
||||||
call db1_secret.stamp(2);
|
call db1_secret.stamp(2);
|
||||||
|
select db1_secret.db();
|
||||||
|
|
||||||
# ...but not this
|
# ...but not this
|
||||||
--error 1044
|
--error 1044
|
||||||
@ -53,6 +59,7 @@ connection con3anon;
|
|||||||
|
|
||||||
# This should work...
|
# This should work...
|
||||||
call db1_secret.stamp(3);
|
call db1_secret.stamp(3);
|
||||||
|
select db1_secret.db();
|
||||||
|
|
||||||
# ...but not this
|
# ...but not this
|
||||||
--error 1044
|
--error 1044
|
||||||
@ -71,9 +78,14 @@ alter procedure stamp sql security invoker;
|
|||||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||||
show procedure status like 'stamp';
|
show procedure status like 'stamp';
|
||||||
|
|
||||||
|
alter function db sql security invoker;
|
||||||
|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||||
|
show function status like 'db';
|
||||||
|
|
||||||
# root still can
|
# root still can
|
||||||
call stamp(4);
|
call stamp(4);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
select db();
|
||||||
|
|
||||||
#
|
#
|
||||||
# User1 cannot
|
# User1 cannot
|
||||||
@ -83,6 +95,8 @@ connection con2user1;
|
|||||||
# This should not work
|
# This should not work
|
||||||
--error 1044
|
--error 1044
|
||||||
call db1_secret.stamp(5);
|
call db1_secret.stamp(5);
|
||||||
|
--error 1044
|
||||||
|
select db1_secret.db();
|
||||||
|
|
||||||
#
|
#
|
||||||
# Anonymous cannot
|
# Anonymous cannot
|
||||||
@ -92,7 +106,8 @@ connection con3anon;
|
|||||||
# This should not work
|
# This should not work
|
||||||
--error 1044
|
--error 1044
|
||||||
call db1_secret.stamp(6);
|
call db1_secret.stamp(6);
|
||||||
|
--error 1044
|
||||||
|
select db1_secret.db();
|
||||||
|
|
||||||
#
|
#
|
||||||
# BUG#2777
|
# BUG#2777
|
||||||
@ -149,6 +164,7 @@ select * from t2;
|
|||||||
# Clean up
|
# Clean up
|
||||||
connection con1root;
|
connection con1root;
|
||||||
drop procedure db1_secret.stamp;
|
drop procedure db1_secret.stamp;
|
||||||
|
drop function db1_secret.db;
|
||||||
drop procedure db2.p;
|
drop procedure db2.p;
|
||||||
drop procedure db2.q;
|
drop procedure db2.q;
|
||||||
use test;
|
use test;
|
||||||
|
@ -3120,7 +3120,11 @@ Item_func_sp::execute(Item **itp)
|
|||||||
if (! m_sp)
|
if (! m_sp)
|
||||||
m_sp= sp_find_function(thd, m_name);
|
m_sp= sp_find_function(thd, m_name);
|
||||||
if (! m_sp)
|
if (! m_sp)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
|
||||||
|
"FUNCTION", m_name->m_qname);
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
sp_change_security_context(thd, m_sp, &save_ctx);
|
sp_change_security_context(thd, m_sp, &save_ctx);
|
||||||
@ -3147,6 +3151,8 @@ Item_func_sp::field_type() const
|
|||||||
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
|
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
|
||||||
DBUG_RETURN(m_sp->m_returns);
|
DBUG_RETURN(m_sp->m_returns);
|
||||||
}
|
}
|
||||||
|
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
|
||||||
|
"FUNCTION", m_name->m_qname);
|
||||||
DBUG_RETURN(MYSQL_TYPE_STRING);
|
DBUG_RETURN(MYSQL_TYPE_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3162,6 +3168,8 @@ Item_func_sp::result_type() const
|
|||||||
{
|
{
|
||||||
DBUG_RETURN(m_sp->result());
|
DBUG_RETURN(m_sp->result());
|
||||||
}
|
}
|
||||||
|
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
|
||||||
|
"FUNCTION", m_name->m_qname);
|
||||||
DBUG_RETURN(STRING_RESULT);
|
DBUG_RETURN(STRING_RESULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3172,7 +3180,12 @@ Item_func_sp::fix_length_and_dec()
|
|||||||
|
|
||||||
if (! m_sp)
|
if (! m_sp)
|
||||||
m_sp= sp_find_function(current_thd, m_name);
|
m_sp= sp_find_function(current_thd, m_name);
|
||||||
if (m_sp)
|
if (! m_sp)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
|
||||||
|
"FUNCTION", m_name->m_qname);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
switch (m_sp->result()) {
|
switch (m_sp->result()) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
|
@ -1107,7 +1107,10 @@ public:
|
|||||||
Item *it;
|
Item *it;
|
||||||
|
|
||||||
if (execute(&it))
|
if (execute(&it))
|
||||||
|
{
|
||||||
|
null_value= 1;
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
}
|
||||||
return it->val();
|
return it->val();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,7 +1119,10 @@ public:
|
|||||||
Item *it;
|
Item *it;
|
||||||
|
|
||||||
if (execute(&it))
|
if (execute(&it))
|
||||||
|
{
|
||||||
|
null_value= 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return it->val_str(str);
|
return it->val_str(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,8 +445,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
|
|||||||
int quick_rm_table(enum db_type base,const char *db,
|
int quick_rm_table(enum db_type base,const char *db,
|
||||||
const char *table_name);
|
const char *table_name);
|
||||||
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 empty_is_ok=0, bool no_access_check=0);
|
|
||||||
void mysql_parse(THD *thd,char *inBuf,uint length);
|
void mysql_parse(THD *thd,char *inBuf,uint length);
|
||||||
bool is_update_query(enum enum_sql_command command);
|
bool is_update_query(enum enum_sql_command command);
|
||||||
void free_items(Item *item);
|
void free_items(Item *item);
|
||||||
|
106
sql/sp.cc
106
sql/sp.cc
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "sql_acl.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sp_cache.h"
|
#include "sp_cache.h"
|
||||||
@ -960,19 +961,104 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
int
|
||||||
sp_change_db(THD *thd, char *db, bool no_access_check)
|
sp_change_db(THD *thd, char *name, bool no_access_check)
|
||||||
{
|
{
|
||||||
int ret;
|
int length, db_length;
|
||||||
ulong dbaccess= thd->db_access; /* mysql_change_db() changes this */
|
char *dbname=my_strdup((char*) name,MYF(MY_WME));
|
||||||
my_bool nsok= thd->net.no_send_ok; /* mysql_change_db() does send_ok() */
|
char path[FN_REFLEN];
|
||||||
thd->net.no_send_ok= TRUE;
|
ulong db_access;
|
||||||
|
HA_CREATE_INFO create;
|
||||||
DBUG_ENTER("sp_change_db");
|
DBUG_ENTER("sp_change_db");
|
||||||
DBUG_PRINT("enter", ("db: %s, no_access_check: %d", db, no_access_check));
|
DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
|
||||||
|
|
||||||
ret= mysql_change_db(thd, db, 1, no_access_check);
|
db_length= (!dbname ? 0 : strip_sp(dbname));
|
||||||
|
if (dbname && db_length)
|
||||||
|
{
|
||||||
|
if ((db_length > NAME_LEN) || check_db_name(dbname))
|
||||||
|
{
|
||||||
|
my_printf_error(ER_WRONG_DB_NAME, ER(ER_WRONG_DB_NAME), MYF(0), dbname);
|
||||||
|
x_free(dbname);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thd->net.no_send_ok= nsok;
|
if (dbname && db_length)
|
||||||
thd->db_access= dbaccess;
|
{
|
||||||
DBUG_RETURN(ret);
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
if (! no_access_check)
|
||||||
|
{
|
||||||
|
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_printf_error(ER_DBACCESS_DENIED_ERROR, ER(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_printf_error(ER_BAD_DB_ERROR, ER(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);
|
||||||
}
|
}
|
||||||
|
@ -389,12 +389,13 @@ sp_head::execute(THD *thd)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ret == 0 && !thd->killed && !thd->query_error);
|
} while (ret == 0 && !thd->killed && !thd->query_error &&
|
||||||
|
!thd->net.report_error);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
|
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
|
||||||
ret, thd->killed, thd->query_error));
|
ret, thd->killed, thd->query_error));
|
||||||
if (thd->killed || thd->query_error)
|
if (thd->killed || thd->query_error || thd->net.report_error)
|
||||||
ret= -1;
|
ret= -1;
|
||||||
/* If the DB has changed, the pointer has changed too, but the
|
/* If the DB has changed, the pointer has changed too, but the
|
||||||
original thd->db will then have been freed */
|
original thd->db will then have been freed */
|
||||||
@ -553,7 +554,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
ret= execute(thd);
|
ret= execute(thd);
|
||||||
|
|
||||||
// Don't copy back OUT values if we got an error
|
// Don't copy back OUT values if we got an error
|
||||||
if (ret == 0 && csize > 0)
|
if (ret)
|
||||||
|
{
|
||||||
|
if (thd->net.report_error)
|
||||||
|
send_error(thd, 0, NullS);
|
||||||
|
}
|
||||||
|
else if (csize > 0)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Item> li(*args);
|
List_iterator_fast<Item> li(*args);
|
||||||
Item *it;
|
Item *it;
|
||||||
|
@ -595,8 +595,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
|||||||
1 error
|
1 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool mysql_change_db(THD *thd, const char *name,
|
bool mysql_change_db(THD *thd, const char *name)
|
||||||
bool empty_is_ok, 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));
|
||||||
@ -605,76 +604,62 @@ bool mysql_change_db(THD *thd, const char *name,
|
|||||||
HA_CREATE_INFO create;
|
HA_CREATE_INFO create;
|
||||||
DBUG_ENTER("mysql_change_db");
|
DBUG_ENTER("mysql_change_db");
|
||||||
|
|
||||||
if ((!dbname || !(db_length=strip_sp(dbname))) && !empty_is_ok)
|
if (!dbname || !(db_length=strip_sp(dbname)))
|
||||||
{
|
{
|
||||||
x_free(dbname); /* purecov: inspected */
|
x_free(dbname); /* purecov: inspected */
|
||||||
send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
|
send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
}
|
}
|
||||||
if (!empty_is_ok || (dbname && db_length))
|
if ((db_length > NAME_LEN) || check_db_name(dbname))
|
||||||
{
|
{
|
||||||
if ((db_length > NAME_LEN) || check_db_name(dbname))
|
net_printf(thd, ER_WRONG_DB_NAME, dbname);
|
||||||
{
|
x_free(dbname);
|
||||||
net_printf(thd, ER_WRONG_DB_NAME, dbname);
|
DBUG_RETURN(1);
|
||||||
x_free(dbname);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DBUG_PRINT("info",("Use database: %s", dbname));
|
DBUG_PRINT("info",("Use database: %s", dbname));
|
||||||
if (!empty_is_ok || (dbname && db_length))
|
|
||||||
{
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (! no_access_check)
|
if (test_all_bits(thd->master_access,DB_ACLS))
|
||||||
{
|
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) &&
|
net_printf(thd,ER_DBACCESS_DENIED_ERROR,
|
||||||
(!grant_option || check_grant_db(thd,dbname)))
|
thd->priv_user,
|
||||||
{
|
thd->priv_host,
|
||||||
net_printf(thd,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,
|
||||||
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
|
dbname);
|
||||||
thd->priv_user,
|
my_free(dbname,MYF(0));
|
||||||
thd->priv_host,
|
DBUG_RETURN(1);
|
||||||
dbname);
|
}
|
||||||
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);
|
||||||
length=unpack_dirname(path,path); // Convert if not unix
|
length=unpack_dirname(path,path); // Convert if not unix
|
||||||
if (length && path[length-1] == FN_LIBCHAR)
|
if (length && path[length-1] == FN_LIBCHAR)
|
||||||
path[length-1]=0; // remove ending '\'
|
path[length-1]=0; // remove ending '\'
|
||||||
if (access(path,F_OK))
|
if (access(path,F_OK))
|
||||||
{
|
{
|
||||||
net_printf(thd,ER_BAD_DB_ERROR,dbname);
|
net_printf(thd,ER_BAD_DB_ERROR,dbname);
|
||||||
my_free(dbname,MYF(0));
|
my_free(dbname,MYF(0));
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
send_ok(thd);
|
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;
|
||||||
if (!empty_is_ok || (dbname && db_length))
|
|
||||||
{
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (! no_access_check)
|
thd->db_access=db_access;
|
||||||
thd->db_access=db_access;
|
|
||||||
#endif
|
#endif
|
||||||
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
|
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
|
||||||
load_db_opt(thd, path, &create);
|
load_db_opt(thd, path, &create);
|
||||||
thd->db_charset= create.default_table_charset ?
|
thd->db_charset= create.default_table_charset ?
|
||||||
create.default_table_charset :
|
create.default_table_charset :
|
||||||
thd->variables.collation_server;
|
thd->variables.collation_server;
|
||||||
thd->variables.collation_database= thd->db_charset;
|
thd->variables.collation_database= thd->db_charset;
|
||||||
}
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
153
sql/sql_yacc.yy
153
sql/sql_yacc.yy
@ -3923,83 +3923,90 @@ simple_expr:
|
|||||||
{ $$= new Item_func_round($3,$5,1); }
|
{ $$= new Item_func_round($3,$5,1); }
|
||||||
| TRUE_SYM
|
| TRUE_SYM
|
||||||
{ $$= new Item_int((char*) "TRUE",1,1); }
|
{ $$= new Item_int((char*) "TRUE",1,1); }
|
||||||
| IDENT_sys '(' udf_expr_list ')'
|
| ident '.' ident '(' udf_expr_list ')'
|
||||||
{
|
{
|
||||||
sp_name *name= sp_name_current_db_new(YYTHD, $1);
|
LEX *lex= Lex;
|
||||||
|
sp_name *name= new sp_name($1, $3);
|
||||||
|
|
||||||
if (sp_function_exists(YYTHD, name))
|
name->init_qname(YYTHD);
|
||||||
{
|
sp_add_fun_to_lex(Lex, name);
|
||||||
LEX *lex= Lex;
|
if ($5)
|
||||||
|
$$= new Item_func_sp(name, *$5);
|
||||||
sp_add_fun_to_lex(lex, name);
|
|
||||||
if ($3)
|
|
||||||
$$= new Item_func_sp(name, *$3);
|
|
||||||
else
|
|
||||||
$$= new Item_func_sp(name);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
$$= new Item_func_sp(name);
|
||||||
#ifdef HAVE_DLOPEN
|
|
||||||
udf_func *udf;
|
|
||||||
|
|
||||||
if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
|
|
||||||
{
|
|
||||||
switch (udf->returns) {
|
|
||||||
case STRING_RESULT:
|
|
||||||
if (udf->type == UDFTYPE_FUNCTION)
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_str(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_str(udf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_str(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_str(udf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REAL_RESULT:
|
|
||||||
if (udf->type == UDFTYPE_FUNCTION)
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_float(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_float(udf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_float(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_float(udf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INT_RESULT:
|
|
||||||
if (udf->type == UDFTYPE_FUNCTION)
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_int(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_int(udf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_int(udf, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_int(udf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
YYABORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* HAVE_DLOPEN */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
| IDENT_sys '(' udf_expr_list ')'
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DLOPEN
|
||||||
|
udf_func *udf;
|
||||||
|
|
||||||
|
if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
|
||||||
|
{
|
||||||
|
switch (udf->returns) {
|
||||||
|
case STRING_RESULT:
|
||||||
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_func_udf_str(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_str(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_str(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_str(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REAL_RESULT:
|
||||||
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_func_udf_float(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_float(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_float(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_float(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_func_udf_int(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_int(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_int(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_int(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* HAVE_DLOPEN */
|
||||||
|
{
|
||||||
|
sp_name *name= sp_name_current_db_new(YYTHD, $1);
|
||||||
|
|
||||||
|
sp_add_fun_to_lex(Lex, name);
|
||||||
|
if ($3)
|
||||||
|
$$= new Item_func_sp(name, *$3);
|
||||||
|
else
|
||||||
|
$$= new Item_func_sp(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
|
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
|
||||||
{
|
{
|
||||||
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
|
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
|
||||||
|
Reference in New Issue
Block a user