Merge remote-tracking branch 'origin/bb-10.2-ext' into 10.3

This commit is contained in:
Alexander Barkov 2017-07-31 23:00:59 +04:00
commit c431eafd62
29 changed files with 1098 additions and 781 deletions

View File

@ -755,3 +755,21 @@ GRANT EXECUTE ON PROCEDURE `test`.`sp1` TO 'root'@'localhost'
GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION
drop procedure sp1;
set password='';
#
# MDEV-13396 Unexpected "alter routine comand defined" during CREATE OR REPLACE PROCEDURE
#
CREATE DATABASE u1;
CREATE PROCEDURE u1.p1() BEGIN SELECT 1; END; $$
CREATE FUNCTION u1.f1() RETURNS INT BEGIN RETURN 1; END; $$
CREATE USER u1@localhost;
GRANT CREATE ROUTINE ON u1.* TO u1@localhost;
GRANT ALTER ROUTINE ON FUNCTION u1.f1 TO u1@localhost;
GRANT ALTER ROUTINE ON PROCEDURE u1.p1 TO u1@localhost;
connect u1, localhost, u1,,;
USE u1;
CREATE OR REPLACE FUNCTION f1() RETURNS INT BEGIN RETURN 2; END; $$
CREATE OR REPLACE PROCEDURE p1() BEGIN SELECT 1; END; $$
disconnect u1;
connection default;
DROP DATABASE u1;
DROP USER u1@localhost;

View File

@ -2762,10 +2762,8 @@ CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (3), (1), (2);
SELECT i, ROW_NUMBER() OVER () FROM t1 WHERE 1 = 2;
i ROW_NUMBER() OVER ()
NULL 1
SELECT i, COUNT(*) OVER () FROM t1 WHERE 1 = 2;
i COUNT(*) OVER ()
NULL 1
DROP TABLE t1;
#
# MDEV-12051: window function in query with implicit grouping
@ -3142,6 +3140,40 @@ sum(i) over (order by i) interval(sum(i) over (order by i), 10, 20)
63 2
drop table t1;
#
# MDEV-13352: Server crashes in st_join_table::remove_duplicates
#
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1),(2);
SELECT DISTINCT ROW_NUMBER() OVER(), i FROM t1 WHERE 0;
ROW_NUMBER() OVER() i
SELECT ROW_NUMBER() OVER(), i FROM t1 WHERE 0;
ROW_NUMBER() OVER() i
DROP TABLE t1;
#
# MDEV-13344: Server crashes in in AGGR_OP::put_record on subquery
# with window function and constant table
# (Testcase only)
#
CREATE TABLE t1 (c CHAR(8)) ENGINE=MyISAM;
INSERT IGNORE INTO t1 VALUES ('foo');
SELECT ('bar',1) IN ( SELECT c, ROW_NUMBER() OVER (PARTITION BY c) FROM t1);
('bar',1) IN ( SELECT c, ROW_NUMBER() OVER (PARTITION BY c) FROM t1)
0
DROP TABLE t1;
#
# MDEV-13351: Server crashes in st_select_lex::set_explain_type upon UNION with window function
#
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1),(2);
SELECT Nth_value(i,1) OVER() FROM t1
UNION ALL
( SELECT Nth_value(i,2) OVER() FROM t1 LIMIT 0 )
;
Nth_value(i,1) OVER()
1
1
DROP TABLE t1;
#
# Start of 10.3 tests
#
#

View File

@ -11,10 +11,6 @@ c1 c2
4 manual_insert_2
11 should repeat 4 times [11-14]
12 should repeat 4 times [11-14]
13 should repeat 4 times [11-14]
14 should repeat 4 times [11-14]
2 should_have_2
NULL should_have_NULL
DELETE FROM t1;
EXECUTE populate_table;
INSERT INTO t1

View File

@ -1023,3 +1023,30 @@ grant execute on procedure sp1 to current_user() identified by 'barfoo';
show grants;
drop procedure sp1;
set password='';
--echo #
--echo # MDEV-13396 Unexpected "alter routine comand defined" during CREATE OR REPLACE PROCEDURE
--echo #
CREATE DATABASE u1;
DELIMITER $$;
CREATE PROCEDURE u1.p1() BEGIN SELECT 1; END; $$
CREATE FUNCTION u1.f1() RETURNS INT BEGIN RETURN 1; END; $$
DELIMITER ;$$
CREATE USER u1@localhost;
GRANT CREATE ROUTINE ON u1.* TO u1@localhost;
GRANT ALTER ROUTINE ON FUNCTION u1.f1 TO u1@localhost;
GRANT ALTER ROUTINE ON PROCEDURE u1.p1 TO u1@localhost;
connect (u1, localhost, u1,,);
USE u1;
DELIMITER $$;
CREATE OR REPLACE FUNCTION f1() RETURNS INT BEGIN RETURN 2; END; $$
CREATE OR REPLACE PROCEDURE p1() BEGIN SELECT 1; END; $$
DELIMITER ;$$
disconnect u1;
connection default;
DROP DATABASE u1;
DROP USER u1@localhost;

View File

@ -1924,6 +1924,36 @@ select sum(i) over (order by i), interval(sum(i) over (order by i), 10, 20)
from t1;
drop table t1;
--echo #
--echo # MDEV-13352: Server crashes in st_join_table::remove_duplicates
--echo #
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1),(2);
SELECT DISTINCT ROW_NUMBER() OVER(), i FROM t1 WHERE 0;
SELECT ROW_NUMBER() OVER(), i FROM t1 WHERE 0;
DROP TABLE t1;
--echo #
--echo # MDEV-13344: Server crashes in in AGGR_OP::put_record on subquery
--echo # with window function and constant table
--echo # (Testcase only)
--echo #
CREATE TABLE t1 (c CHAR(8)) ENGINE=MyISAM;
INSERT IGNORE INTO t1 VALUES ('foo');
SELECT ('bar',1) IN ( SELECT c, ROW_NUMBER() OVER (PARTITION BY c) FROM t1);
DROP TABLE t1;
--echo #
--echo # MDEV-13351: Server crashes in st_select_lex::set_explain_type upon UNION with window function
--echo #
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1),(2);
SELECT Nth_value(i,1) OVER() FROM t1
UNION ALL
( SELECT Nth_value(i,2) OVER() FROM t1 LIMIT 0 )
;
DROP TABLE t1;
--echo #
--echo # Start of 10.3 tests
--echo #

View File

@ -10773,3 +10773,22 @@ void Field::register_field_in_read_map()
}
bitmap_set_bit(table->read_set, field_index);
}
bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
{
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc= false;
THD *thd= get_thd();
sql_mode_t sql_mode_backup= thd->variables.sql_mode;
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
val_str(&str);
if (!(to->length= str.length()))
*to= empty_clex_str;
else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length()))))
to->length= 0;
thd->variables.sql_mode= sql_mode_backup;
return rc;
}

View File

@ -839,6 +839,21 @@ public:
*/
virtual String *val_str(String*,String *)=0;
String *val_int_as_str(String *val_buffer, bool unsigned_flag);
/*
Return the field value as a LEX_CSTRING, without padding to full length
(MODE_PAD_CHAR_TO_FULL_LENGTH is temporarily suppressed during the call).
In case of an empty value, to[0] is assigned to empty_clex_string,
memory is not allocated.
In case of a non-empty value, the memory is allocated on mem_root.
In case of a memory allocation failure, to[0] is assigned to {NULL,0}.
@param [IN] mem_root store non-empty values here
@param [OUT to return the string here
@retval false (success)
@retval true (EOM)
*/
bool val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to);
fast_field_copier get_fast_field_copier(const Field *from);
/*
str_needs_quotes() returns TRUE if the value returned by val_str() needs

View File

@ -3424,7 +3424,7 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
arg_count= item_list->elements;
qname= new (thd->mem_root) sp_name(db, name, use_explicit_name);
sp_add_used_routine(lex, thd, qname, TYPE_ENUM_FUNCTION);
sp_handler_function.add_used_routine(lex, thd, qname);
if (arg_count > 0)
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname,

View File

@ -6265,8 +6265,7 @@ Item_func_sp::init_result_field(THD *thd)
DBUG_ASSERT(m_sp == NULL);
DBUG_ASSERT(sp_result_field == NULL);
if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
&thd->sp_func_cache, TRUE)))
if (!(m_sp= sp_handler_function.sp_find_routine(thd, m_name, true)))
{
my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
context->process_error(thd);
@ -6515,7 +6514,8 @@ Item_func_sp::sp_check_access(THD *thd)
DBUG_ENTER("Item_func_sp::sp_check_access");
DBUG_ASSERT(m_sp);
if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
m_sp->m_db.str, m_sp->m_name.str,
&sp_handler_function, false))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
@ -6541,7 +6541,8 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
thd->security_ctx= context->security_ctx;
res= check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str,
m_name->m_name.str, 0, FALSE);
m_name->m_name.str,
&sp_handler_function, false);
thd->security_ctx= save_security_ctx;
if (res)
@ -6584,7 +6585,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
Try to set and restore the security context to see whether it's valid
*/
Security_context *save_secutiry_ctx;
res= set_routine_security_ctx(thd, m_sp, false, &save_secutiry_ctx);
res= set_routine_security_ctx(thd, m_sp, &save_secutiry_ctx);
if (!res)
m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);

628
sql/sp.cc

File diff suppressed because it is too large Load Diff

329
sql/sp.h
View File

@ -17,7 +17,10 @@
#ifndef _SP_H_
#define _SP_H_
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_string.h" // LEX_STRING
#include "sql_cmd.h"
#include "mdl.h"
class Field;
class Open_tables_backup;
@ -28,8 +31,10 @@ class Sroutine_hash_entry;
class THD;
class sp_cache;
class sp_head;
class sp_name;
class sp_pcontext;
class Database_qualified_name;
struct st_sp_chistics;
class Stored_program_creation_ctx;
struct LEX;
struct TABLE;
struct TABLE_LIST;
@ -49,19 +54,268 @@ enum stored_procedure_type
};
static inline const char *
stored_procedure_type_to_str(enum stored_procedure_type type)
class Sp_handler
{
int db_find_routine_aux(THD *thd, const Database_qualified_name *name,
TABLE *table) const;
int db_find_routine(THD *thd, const Database_qualified_name *name,
sp_head **sphp) const;
int db_load_routine(THD *thd, const Database_qualified_name *name,
sp_head **sphp,
sql_mode_t sql_mode,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
longlong created, longlong modified,
Stored_program_creation_ctx *creation_ctx) const;
int sp_drop_routine_internal(THD *thd,
const Database_qualified_name *name,
TABLE *table) const;
public:
static const Sp_handler *handler(enum enum_sql_command cmd);
static const Sp_handler *handler(stored_procedure_type type);
static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
const char *type_str() const { return type_lex_cstring().str; }
virtual const char *show_create_routine_col1_caption() const
{
DBUG_ASSERT(0);
return "";
}
virtual const char *show_create_routine_col3_caption() const
{
DBUG_ASSERT(0);
return "";
}
virtual stored_procedure_type type() const= 0;
virtual LEX_CSTRING type_lex_cstring() const= 0;
virtual LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("???")};
DBUG_ASSERT(0);
return m_empty_body;
}
virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0;
virtual sp_cache **get_cache(THD *) const { return NULL; }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
virtual HASH *get_priv_hash() const { return NULL; }
#endif
virtual ulong recursion_depth(THD *thd) const { return 0; }
/**
Return appropriate error about recursion limit reaching
@param thd Thread handle
@param sp SP routine
@remark For functions and triggers we return error about
prohibited recursion. For stored procedures we
return about reaching recursion limit.
*/
virtual void recursion_level_error(THD *thd, const sp_head *sp) const
{
my_error(ER_SP_NO_RECURSION, MYF(0));
}
virtual bool add_instr_freturn(THD *thd, sp_head *sp,
sp_pcontext *spcont,
Item *item, LEX *lex) const;
virtual bool add_instr_preturn(THD *thd, sp_head *sp,
sp_pcontext *spcont) const;
void add_used_routine(Query_tables_list *prelocking_ctx,
Query_arena *arena,
const Database_qualified_name *rt) const;
sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name,
bool cache_only) const;
int sp_cache_routine(THD *thd, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const;
bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
bool sp_show_create_routine(THD *thd,
const Database_qualified_name *name) const;
bool sp_create_routine(THD *thd, const sp_head *sp) const;
int sp_update_routine(THD *thd, const Database_qualified_name *name,
const st_sp_chistics *chistics) const;
int sp_drop_routine(THD *thd, const Database_qualified_name *name) const;
sp_head *sp_load_for_information_schema(THD *thd, TABLE *proc_table,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
sql_mode_t sql_mode,
bool *free_sp_head) const;
bool show_create_sp(THD *thd, String *buf,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
sql_mode_t sql_mode) const;
};
class Sp_handler_procedure: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PROCEDURE")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Procedure";
}
const char *show_create_routine_col3_caption() const
{
return "Create Procedure";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::PROCEDURE;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
ulong recursion_depth(THD *thd) const;
void recursion_level_error(THD *thd, const sp_head *sp) const;
bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const;
};
class Sp_handler_function: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("FUNCTION")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("RETURN NULL")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Function";
}
const char *show_create_routine_col3_caption() const
{
return "Create Function";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::FUNCTION;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont,
Item *item, LEX *lex) const;
};
class Sp_handler_trigger: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("TRIGGER")};
return m_type_str;
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
DBUG_ASSERT(0);
return MDL_key::TRIGGER;
}
};
extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
{
switch (cmd) {
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_STATUS_PROC:
return &sp_handler_procedure;
case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_ALTER_FUNCTION:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_SHOW_FUNC_CODE:
case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_STATUS_FUNC:
return &sp_handler_function;
default:
break;
}
return NULL;
}
inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
{
switch (type) {
case TYPE_ENUM_PROCEDURE: return "PROCEDURE";
case TYPE_ENUM_FUNCTION: return "FUNCTION";
case TYPE_ENUM_TRIGGER: return "TRIGGER";
case TYPE_ENUM_PROXY: return "PROXY";
case TYPE_ENUM_PROCEDURE:
return &sp_handler_procedure;
case TYPE_ENUM_FUNCTION:
return &sp_handler_function;
case TYPE_ENUM_TRIGGER:
return &sp_handler_trigger;
case TYPE_ENUM_PROXY:
break;
}
DBUG_ASSERT(0);
return "UNKNOWN_STORED_";
return NULL;
}
inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type)
{
switch (type) {
case MDL_key::FUNCTION:
return &sp_handler_function;
case MDL_key::PROCEDURE:
return &sp_handler_procedure;
case MDL_key::GLOBAL:
case MDL_key::SCHEMA:
case MDL_key::TABLE:
case MDL_key::TRIGGER:
case MDL_key::EVENT:
case MDL_key::COMMIT:
case MDL_key::USER_LOCK:
case MDL_key::NAMESPACE_END:
break;
}
return NULL;
}
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
@ -121,36 +375,6 @@ sp_drop_db_routines(THD *thd, const char *db);
*/
bool lock_db_routines(THD *thd, const char *db);
sp_head *
sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
sp_cache **cp, bool cache_only);
int
sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
bool lookup_only, sp_head **sp);
int
sp_cache_routine(THD *thd, stored_procedure_type type, const sp_name *name,
bool lookup_only, sp_head **sp);
bool
sp_exist_routines(THD *thd, TABLE_LIST *procs, bool is_proc);
bool
sp_show_create_routine(THD *thd, stored_procedure_type type, const sp_name *name);
bool
sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp);
int
sp_update_routine(THD *thd, stored_procedure_type type, const sp_name *name,
const st_sp_chistics *chistics);
int
sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name);
/**
Structure that represents element in the set of stored routines
used by statement or routine.
@ -185,14 +409,11 @@ public:
changes.
*/
ulong m_sp_cache_version;
int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const;
};
/*
Procedures for handling sets of stored routines used by statement or routine.
*/
void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const sp_name *rt, stored_procedure_type rt_type);
bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const MDL_key *key, TABLE_LIST *belong_to_view);
void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
@ -212,13 +433,6 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
*/
TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup);
sp_head *
sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
String *name, sql_mode_t sql_mode,
stored_procedure_type type,
const char *returns, const char *params,
bool *free_sp_head);
bool load_charset(MEM_ROOT *mem_root,
Field *field,
CHARSET_INFO *dflt_cs,
@ -231,17 +445,6 @@ bool load_collation(MEM_ROOT *mem_root,
void sp_returns_type(THD *thd,
String &result,
sp_head *sp);
const sp_head *sp);
bool show_create_sp(THD *thd, String *buf,
stored_procedure_type type,
const char *db, ulong dblen,
const char *name, ulong namelen,
const char *params, ulong paramslen,
const char *returns, ulong returnslen,
const char *body, ulong bodylen,
const st_sp_chistics &chistics,
const LEX_CSTRING *definer_user,
const LEX_CSTRING *definer_host,
sql_mode_t sql_mode);
#endif /* _SP_H_ */

View File

@ -540,10 +540,10 @@ sp_head::operator delete(void *ptr, size_t size) throw()
}
sp_head::sp_head(stored_procedure_type type)
sp_head::sp_head(const Sp_handler *sph)
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
Database_qualified_name(&null_clex_str, &null_clex_str),
m_type(type),
m_handler(sph),
m_flags(0),
m_explicit_name(false),
/*
@ -610,7 +610,7 @@ sp_head::init(LEX *lex)
void
sp_head::init_sp_name(THD *thd, sp_name *spname)
sp_head::init_sp_name(THD *thd, const sp_name *spname)
{
DBUG_ENTER("sp_head::init_sp_name");
@ -733,7 +733,7 @@ sp_head::~sp_head()
Field *
sp_head::create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
TABLE *table)
TABLE *table) const
{
Field *field;
LEX_CSTRING name;
@ -960,30 +960,15 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
}
/**
Return appropriate error about recursion limit reaching
@param thd Thread handle
@remark For functions and triggers we return error about
prohibited recursion. For stored procedures we
return about reaching recursion limit.
*/
void sp_head::recursion_level_error(THD *thd)
void Sp_handler_procedure::recursion_level_error(THD *thd,
const sp_head *sp) const
{
if (m_type == TYPE_ENUM_PROCEDURE)
{
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
static_cast<int>(thd->variables.max_sp_recursion_depth),
m_name.str);
}
else
my_error(ER_SP_NO_RECURSION, MYF(0));
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
static_cast<int>(thd->variables.max_sp_recursion_depth),
sp->m_name.str);
}
/**
Execute the routine. The main instruction jump loop is there.
Assume the parameters already set.
@ -1391,7 +1376,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
@param thd thread handle
@param sp stored routine to change the context for
@param is_proc TRUE is procedure, FALSE if function
@param save_ctx pointer to an old security context
@todo
@ -1406,8 +1390,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
*/
bool
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
Security_context **save_ctx)
set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx)
{
*save_ctx= 0;
if (sp->suid() != SP_IS_NOT_SUID &&
@ -1429,7 +1412,7 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
*/
if (*save_ctx &&
check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, is_proc, FALSE))
sp->m_db.str, sp->m_name.str, sp->m_handler, false))
{
sp->m_security_ctx.restore_security_context(thd, *save_ctx);
*save_ctx= 0;
@ -1450,20 +1433,17 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
so we can omit the security context switch for performance purposes.
@param thd
@param sphead
@param is_proc
@param root_pctx
@param ret_value
@retval NULL - error (access denided or EOM)
@retval !NULL - success (the invoker has rights to all %TYPE tables)
*/
sp_rcontext *sp_head::rcontext_create(THD *thd, bool is_proc, Field *ret_value)
sp_rcontext *sp_head::rcontext_create(THD *thd, Field *ret_value)
{
bool has_column_type_refs= m_flags & HAS_COLUMN_TYPE_REFS;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx;
if (has_column_type_refs &&
set_routine_security_ctx(thd, this, is_proc, &save_security_ctx))
set_routine_security_ctx(thd, this, &save_security_ctx))
return NULL;
#endif
sp_rcontext *res= sp_rcontext::create(thd, m_pcont, ret_value,
@ -1689,7 +1669,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
if (!(nctx= rcontext_create(thd, false, return_value_fld)))
if (!(nctx= rcontext_create(thd, return_value_fld)))
{
thd->restore_active_arena(&call_arena, &backup_arena);
err_status= TRUE;
@ -1760,7 +1740,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx;
if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx))
if (set_routine_security_ctx(thd, this, &save_security_ctx))
{
err_status= TRUE;
goto err_with_cleanup;
@ -1904,7 +1884,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (! octx)
{
/* Create a temporary old context. */
if (!(octx= rcontext_create(thd, true, NULL)))
if (!(octx= rcontext_create(thd, NULL)))
{
DBUG_PRINT("error", ("Could not create octx"));
DBUG_RETURN(TRUE);
@ -1919,7 +1899,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd;
}
if (!(nctx= rcontext_create(thd, true, NULL)))
if (!(nctx= rcontext_create(thd, NULL)))
{
delete nctx; /* Delete nctx if it was init() that failed. */
thd->spcont= save_spcont;
@ -2042,7 +2022,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx= 0;
if (!err_status)
err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
err_status= set_routine_security_ctx(thd, this, &save_security_ctx);
#endif
if (!err_status)
@ -2458,27 +2438,6 @@ sp_head::set_info(longlong created, longlong modified,
}
void
sp_head::set_definer(const char *definer, uint definerlen)
{
char user_name_holder[USERNAME_LENGTH + 1];
LEX_CSTRING user_name= { user_name_holder, USERNAME_LENGTH };
char host_name_holder[HOSTNAME_LENGTH + 1];
LEX_CSTRING host_name= { host_name_holder, HOSTNAME_LENGTH };
if (parse_user(definer, definerlen, user_name_holder, &user_name.length,
host_name_holder, &host_name.length) &&
user_name.length && !host_name.length)
{
// 'user@' -> 'user@%'
host_name= host_not_specified;
}
set_definer(&user_name, &host_name);
}
void
sp_head::reset_thd_mem_root(THD *thd)
{
@ -2553,7 +2512,7 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
thd->security_ctx->priv_host)));
if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
sp->m_type == TYPE_ENUM_PROCEDURE);
sp->m_handler);
return 0;
}
@ -2562,9 +2521,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
Collect metadata for SHOW CREATE statement for stored routines.
@param thd Thread context.
@param type Stored routine type
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param sph Stored routine handler
@param fields Item list to populate
@return Error status.
@retval FALSE on success
@ -2572,13 +2530,11 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
*/
void
sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
sp_head::show_create_routine_get_fields(THD *thd, const Sp_handler *sph,
List<Item> *fields)
{
const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
"Procedure" : "Function";
const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
"Create Procedure" : "Create Function";
const char *col1_caption= sph->show_create_routine_col1_caption();
const char *col3_caption= sph->show_create_routine_col3_caption();
MEM_ROOT *mem_root= thd->mem_root;
@ -2625,8 +2581,7 @@ sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
Implement SHOW CREATE statement for stored routines.
@param thd Thread context.
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param sph Stored routine handler
@return Error status.
@retval FALSE on success
@ -2634,13 +2589,10 @@ sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
*/
bool
sp_head::show_create_routine(THD *thd, int type)
sp_head::show_create_routine(THD *thd, const Sp_handler *sph)
{
const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
"Procedure" : "Function";
const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
"Create Procedure" : "Create Function";
const char *col1_caption= sph->show_create_routine_col1_caption();
const char *col3_caption= sph->show_create_routine_col3_caption();
bool err_status;
@ -2655,9 +2607,6 @@ sp_head::show_create_routine(THD *thd, int type)
DBUG_ENTER("sp_head::show_create_routine");
DBUG_PRINT("info", ("routine %s", m_name.str));
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
if (check_show_routine_access(thd, this, &full_access))
DBUG_RETURN(TRUE);
@ -2784,6 +2733,29 @@ bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd,
}
bool sp_head::add_instr_freturn(THD *thd, sp_pcontext *spcont,
Item *item, LEX *lex)
{
sp_instr_freturn *i= new (thd->mem_root)
sp_instr_freturn(instructions(), spcont, item,
m_return_field_def.type_handler(), thd->lex);
if (i == NULL || add_instr(i))
return true;
m_flags|= sp_head::HAS_RETURN;
return false;
}
bool sp_head::add_instr_preturn(THD *thd, sp_pcontext *spcont)
{
sp_instr_preturn *i= new (thd->mem_root)
sp_instr_preturn(instructions(), spcont);
if (i == NULL || add_instr(i))
return true;
return false;
}
/*
Replace an instruction at position to "no operation".

View File

@ -40,11 +40,6 @@
@{
*/
// Values for the type enum. This reflects the order of the enum declaration
// in the CREATE TABLE command.
//#define TYPE_ENUM_FUNCTION 1 #define TYPE_ENUM_PROCEDURE 2 #define
//TYPE_ENUM_TRIGGER 3 #define TYPE_ENUM_PROXY 4
Item::Type
sp_map_item_type(enum enum_field_types type);
@ -173,7 +168,7 @@ public:
HAS_COLUMN_TYPE_REFS= 8192
};
stored_procedure_type m_type;
const Sp_handler *m_handler;
uint m_flags; // Boolean attributes of a stored routine
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
@ -220,7 +215,7 @@ public:
m_sp_cache_version= version_arg;
}
sp_rcontext *rcontext_create(THD *thd, bool is_proc, Field *ret_value);
sp_rcontext *rcontext_create(THD *thd, Field *retval);
private:
/**
@ -317,7 +312,7 @@ public:
static void
operator delete(void *ptr, size_t size) throw ();
sp_head(stored_procedure_type type);
sp_head(const Sp_handler *handler);
/// Initialize after we have reset mem_root
void
@ -325,7 +320,7 @@ public:
/** Copy sp name from parser. */
void
init_sp_name(THD *thd, sp_name *spname);
init_sp_name(THD *thd, const sp_name *spname);
/** Set the body-definition start position. */
void
@ -350,10 +345,11 @@ public:
execute_procedure(THD *thd, List<Item> *args);
static void
show_create_routine_get_fields(THD *thd, int type, List<Item> *fields);
show_create_routine_get_fields(THD *thd, const Sp_handler *sph,
List<Item> *fields);
bool
show_create_routine(THD *thd, int type);
show_create_routine(THD *thd, const Sp_handler *sph);
MEM_ROOT *get_main_mem_root() { return &main_mem_root; }
@ -376,6 +372,12 @@ public:
spcont->last_label());
}
bool
add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, LEX *lex);
bool
add_instr_preturn(THD *thd, sp_pcontext *spcont);
Item *adjust_assignment_source(THD *thd, Item *val, Item *val2);
/**
@param thd - the current thd
@ -622,7 +624,7 @@ public:
char *create_string(THD *thd, ulong *lenp);
Field *create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
TABLE *table);
TABLE *table) const;
/**
@ -689,7 +691,12 @@ public:
void set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode);
void set_definer(const char *definer, uint definerlen);
void set_definer(const char *definer, uint definerlen)
{
AUTHID tmp;
tmp.parse(definer, definerlen);
m_definer.copy(mem_root, &tmp.user, &tmp.host);
}
void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name)
{
m_definer.copy(mem_root, user_name, host_name);
@ -713,8 +720,6 @@ public:
*/
void add_mark_lead(uint ip, List<sp_instr> *leads);
void recursion_level_error(THD *thd);
inline sp_instr *
get_instr(uint i)
{
@ -1859,8 +1864,7 @@ void
sp_restore_security_context(THD *thd, Security_context *backup);
bool
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
Security_context **save_ctx);
set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST *

View File

@ -754,6 +754,19 @@ static int traverse_role_graph_down(ACL_USER_BASE *, void *,
int (*) (ACL_USER_BASE *, void *),
int (*) (ACL_USER_BASE *, ACL_ROLE *, void *));
HASH *Sp_handler_procedure::get_priv_hash() const
{
return &proc_priv_hash;
}
HASH *Sp_handler_function::get_priv_hash() const
{
return &func_priv_hash;
}
/*
Enumeration of ACL/GRANT tables in the mysql database
*/
@ -4973,10 +4986,11 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
static GRANT_NAME *
routine_hash_search(const char *host, const char *ip, const char *db,
const char *user, const char *tname, bool proc, bool exact)
const char *user, const char *tname, const Sp_handler *sph,
bool exact)
{
return (GRANT_TABLE*)
name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
name_hash_search(sph->get_priv_hash(),
host, ip, db, user, tname, exact, TRUE);
}
@ -5351,13 +5365,14 @@ table_error:
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo,
const char *db, const char *routine_name,
bool is_proc, ulong rights, bool revoke_grant)
const Sp_handler *sph,
ulong rights, bool revoke_grant)
{
char grantor[USER_HOST_BUFF_SIZE];
int old_row_exists= 1;
int error=0;
ulong store_proc_rights;
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
HASH *hash= sph->get_priv_hash();
DBUG_ENTER("replace_routine_table");
if (revoke_grant && !grant_name->init_privs) // only inherited role privs
@ -5381,9 +5396,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
table->field[4]->store((longlong)(is_proc ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
TRUE);
table->field[4]->store((longlong) sph->type(), true);
store_record(table,record[1]); // store at pos 1
if (table->file->ha_index_read_idx_map(table->record[0], 0,
@ -5503,6 +5516,23 @@ struct PRIVS_TO_MERGE
const char *db, *name;
};
static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type)
{
switch (type) {
case TYPE_ENUM_FUNCTION:
return PRIVS_TO_MERGE::FUNC;
case TYPE_ENUM_PROCEDURE:
return PRIVS_TO_MERGE::PROC;
case TYPE_ENUM_TRIGGER:
case TYPE_ENUM_PROXY:
break;
}
DBUG_ASSERT(0);
return PRIVS_TO_MERGE::PROC;
}
static int init_role_for_merging(ACL_ROLE *role, void *context)
{
role->counter= 0;
@ -6627,7 +6657,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
@param thd Thread handle
@param table_list List of routines to give grant
@param is_proc Is this a list of procedures?
@param sph SP handler
@param user_list List of users to give grant
@param rights Table level grant
@param revoke_grant Is this is a REVOKE command?
@ -6637,7 +6667,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
@retval TRUE An error occurred.
*/
bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
const Sp_handler *sph,
List <LEX_USER> &user_list, ulong rights,
bool revoke_grant, bool write_to_binlog)
{
@ -6657,7 +6688,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
if (!revoke_grant)
{
if (sp_exist_routines(thd, table_list, is_proc))
if (sph->sp_exist_routines(thd, table_list))
DBUG_RETURN(TRUE);
}
@ -6698,7 +6729,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
db_name= table_list->db;
table_name= table_list->table_name;
grant_name= routine_hash_search(Str->host.str, NullS, db_name,
Str->user.str, table_name, is_proc, 1);
Str->user.str, table_name, sph, 1);
if (!grant_name || !grant_name->init_privs)
{
if (revoke_grant)
@ -6712,8 +6743,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
Str->user.str, table_name,
rights, TRUE);
if (!grant_name ||
my_hash_insert(is_proc ?
&proc_priv_hash : &func_priv_hash,(uchar*) grant_name))
my_hash_insert(sph->get_priv_hash(), (uchar*) grant_name))
{
result= TRUE;
continue;
@ -6724,7 +6754,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
instead of TABLE directly. */
if (tables.procs_priv_table().no_such_table() ||
replace_routine_table(thd, grant_name, tables.procs_priv_table().table(),
*Str, db_name, table_name, is_proc, rights,
*Str, db_name, table_name, sph, rights,
revoke_grant) != 0)
{
result= TRUE;
@ -6732,7 +6762,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
}
if (Str->is_role())
propagate_role_grants(find_acl_role(Str->user.str),
is_proc ? PRIVS_TO_MERGE::PROC : PRIVS_TO_MERGE::FUNC,
sp_privs_to_merge(sph->type()),
db_name, table_name);
}
thd->mem_root= old_root;
@ -7341,16 +7371,10 @@ static bool grant_load(THD *thd,
continue;
}
}
if (procs_priv.routine_type()->val_int() == TYPE_ENUM_PROCEDURE)
{
hash= &proc_priv_hash;
}
else
if (procs_priv.routine_type()->val_int() == TYPE_ENUM_FUNCTION)
{
hash= &func_priv_hash;
}
else
uint type= procs_priv.routine_type()->val_int();
const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
type);
if (!sph || !(hash= sph->get_priv_hash()))
{
sql_print_warning("'procs_priv' entry '%s' "
"ignored, bad routine type",
@ -8088,7 +8112,7 @@ bool check_grant_db(THD *thd, const char *db)
thd Thread handler
want_access Bits of privileges user needs to have
procs List of routines to check. The user should have 'want_access'
is_proc True if the list is all procedures, else functions
sph SP handler
no_errors If 0 then we write an error. The error is sent directly to
the client
@ -8098,7 +8122,8 @@ bool check_grant_db(THD *thd, const char *db)
****************************************************************************/
bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_errors)
TABLE_LIST *procs, const Sp_handler *sph,
bool no_errors)
{
TABLE_LIST *table;
Security_context *sctx= thd->security_ctx;
@ -8116,12 +8141,12 @@ bool check_grant_routine(THD *thd, ulong want_access,
{
GRANT_NAME *grant_proc;
if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
table->table_name, is_proc, 0)))
table->table_name, sph, 0)))
table->grant.privilege|= grant_proc->privs;
if (role[0]) /* current role set check */
{
if ((grant_proc= routine_hash_search("", NULL, table->db, role,
table->table_name, is_proc, 0)))
table->table_name, sph, 0)))
table->grant.privilege|= grant_proc->privs;
}
@ -8170,7 +8195,7 @@ err:
*/
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc)
const Sp_handler *sph)
{
bool no_routine_acl= 1;
GRANT_NAME *grant_proc;
@ -8179,7 +8204,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
if ((grant_proc= routine_hash_search(sctx->priv_host,
sctx->ip, db,
sctx->priv_user,
name, is_proc, 0)))
name, sph, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
if (no_routine_acl && sctx->priv_role[0]) /* current set role check */
@ -8187,7 +8212,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
if ((grant_proc= routine_hash_search("",
NULL, db,
sctx->priv_role,
name, is_proc, 0)))
name, sph, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
}
mysql_rwlock_unlock(&LOCK_grant);
@ -10503,6 +10528,45 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
DBUG_RETURN(result);
}
static bool
mysql_revoke_sp_privs(THD *thd,
Grant_tables *tables,
const Sp_handler *sph,
const LEX_USER *lex_user)
{
bool rc= false;
uint counter, revoked;
do {
HASH *hash= sph->get_priv_hash();
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
const char *user,*host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
user= safe_str(grant_proc->user);
host= safe_str(grant_proc->host.hostname);
if (!strcmp(lex_user->user.str, user) &&
!strcmp(lex_user->host.str, host))
{
if (replace_routine_table(thd, grant_proc,
tables->procs_priv_table().table(),
*lex_user,
grant_proc->db, grant_proc->tname,
sph, ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
}
rc= true; // Something went wrong
}
counter++;
}
} while (revoked);
return rc;
}
/*
Revoke all privileges from a list of users.
@ -10519,7 +10583,7 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
uint counter, revoked, is_proc;
uint counter, revoked;
int result;
ACL_DB *acl_db;
DBUG_ENTER("mysql_revoke_all");
@ -10648,32 +10712,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} while (revoked);
/* Remove procedure access */
for (is_proc=0; is_proc<2; is_proc++) do {
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
const char *user,*host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
user= safe_str(grant_proc->user);
host= safe_str(grant_proc->host.hostname);
if (!strcmp(lex_user->user.str,user) &&
!strcmp(lex_user->host.str, host))
{
if (replace_routine_table(thd, grant_proc,
tables.procs_priv_table().table(),
*lex_user,
grant_proc->db, grant_proc->tname,
is_proc, ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
}
result= -1; // Something went wrong
}
counter++;
}
} while (revoked);
if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user))
result= -1;
ACL_USER_BASE *user_or_role;
/* remove role grants */
@ -10825,11 +10866,11 @@ Silence_routine_definer_errors::handle_condition(
*/
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
const Sp_handler *sph)
{
uint counter, revoked;
int result;
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
HASH *hash= sph->get_priv_hash();
Silence_routine_definer_errors error_handler;
DBUG_ENTER("sp_revoke_privileges");
@ -10865,7 +10906,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
if (replace_routine_table(thd, grant_proc,
tables.procs_priv_table().table(), lex_user,
grant_proc->db, grant_proc->tname,
is_proc, ~(ulong)0, 1) == 0)
sph, ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
@ -10890,7 +10931,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
@param thd The current thread.
@param sp_db
@param sp_name
@param is_proc
@param sph
@return
@retval FALSE Success
@ -10898,7 +10939,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
*/
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
const Sp_handler *sph)
{
Security_context *sctx= thd->security_ctx;
LEX_USER *combo;
@ -10960,7 +11001,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
as all errors will be handled later.
*/
thd->push_internal_handler(&error_handler);
result= mysql_routine_grant(thd, tables, is_proc, user_list,
result= mysql_routine_grant(thd, tables, sph, user_list,
DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
thd->pop_internal_handler();
DBUG_RETURN(result);
@ -11746,7 +11787,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
****************************************************************************/
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc)
const Sp_handler *sph)
{
return FALSE;
}

View File

@ -215,7 +215,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights,
bool revoke);
bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
bool mysql_routine_grant(THD *thd, TABLE_LIST *table, const Sp_handler *sph,
List <LEX_USER> &user_list, ulong rights,
bool revoke, bool write_to_binlog);
bool grant_init();
@ -231,7 +231,8 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
bool check_grant_all_columns(THD *thd, ulong want_access,
Field_iterator_table_ref *fields);
bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_error);
TABLE_LIST *procs, const Sp_handler *sph,
bool no_error);
bool check_grant_db(THD *thd,const char *db);
bool check_global_access(THD *thd, ulong want_access, bool no_errors= false);
bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
@ -257,11 +258,11 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc);
const Sp_handler *sph);
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc);
const Sp_handler *sph);
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc);
const Sp_handler *sph);
bool is_acl_user(const char *host, const char *user);
int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);

View File

@ -3127,7 +3127,7 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
DEBUG_SYNC(thd, "after_shared_lock_pname");
/* Ensures the routine is up-to-date and cached, if exists. */
if (sp_cache_routine(thd, rt, has_prelocking_list, &sp))
if (rt->sp_cache_routine(thd, has_prelocking_list, &sp))
DBUG_RETURN(TRUE);
/* Remember the version of the routine in the parse tree. */
@ -3152,7 +3152,7 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
Validating routine version is unnecessary, since CALL
does not affect the prepared statement prelocked list.
*/
if (sp_cache_routine(thd, rt, FALSE, &sp))
if (rt->sp_cache_routine(thd, false, &sp))
DBUG_RETURN(TRUE);
}
}

View File

@ -7475,4 +7475,34 @@ void AUTHID::copy(MEM_ROOT *mem_root, const LEX_CSTRING *user_name,
}
/*
Set from a string in 'user@host' format.
This method resebmles parse_user(),
but does not need temporary buffers.
*/
void AUTHID::parse(const char *str, size_t length)
{
const char *p= strrchr(str, '@');
if (!p)
{
user.str= str;
user.length= length;
host= null_clex_str;
}
else
{
user.str= str;
user.length= (size_t) (p - str);
host.str= p + 1;
host.length= (size_t) (length - user.length - 1);
if (user.length && !host.length)
host= host_not_specified; // 'user@' -> 'user@%'
}
if (user.length > USERNAME_LENGTH)
user.length= USERNAME_LENGTH;
if (host.length > HOSTNAME_LENGTH)
host.length= HOSTNAME_LENGTH;
}
#endif /* !defined(MYSQL_CLIENT) */

View File

@ -4507,10 +4507,16 @@ void st_select_lex::set_explain_type(bool on_the_fly)
if (join)
{
bool uses_cte= false;
for (JOIN_TAB *tab= first_explain_order_tab(join); tab;
tab= next_explain_order_tab(join, tab))
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS,
WITH_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
{
if (tab->table && tab->table->pos_in_table_list->with)
/*
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
*/
if (tab->table && tab->table->pos_in_table_list &&
tab->table->pos_in_table_list->with)
{
uses_cte= true;
break;
@ -5143,7 +5149,7 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name)
{
return sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER &&
name->length == 3 &&
(!my_strcasecmp(system_charset_info, name->str, "NEW") ||
!my_strcasecmp(system_charset_info, name->str, "OLD"));
@ -5819,13 +5825,13 @@ sp_name *LEX::make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2)
}
sp_head *LEX::make_sp_head(THD *thd, sp_name *name,
enum stored_procedure_type type)
sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
const Sp_handler *sph)
{
sp_head *sp;
/* Order is important here: new - reset - init */
if ((sp= new sp_head(type)))
if ((sp= new sp_head(sph)))
{
sp->reset_thd_mem_root(thd);
sp->init(this);
@ -6121,7 +6127,7 @@ bool LEX::maybe_start_compound_statement(THD *thd)
{
if (!sphead)
{
if (!make_sp_head(thd, NULL, TYPE_ENUM_PROCEDURE))
if (!make_sp_head(thd, NULL, &sp_handler_procedure))
return true;
sphead->set_suid(SP_IS_NOT_SUID);
sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());

View File

@ -1287,6 +1287,7 @@ struct st_sp_chistics
enum enum_sp_data_access daccess;
void init() { bzero(this, sizeof(*this)); }
void set(const st_sp_chistics &other) { *this= other; }
bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};
@ -3155,24 +3156,22 @@ public:
void set_stmt_init();
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name);
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2);
sp_head *make_sp_head(THD *thd, sp_name *name,
enum stored_procedure_type type);
sp_head *make_sp_head_no_recursive(THD *thd, sp_name *name,
enum stored_procedure_type type)
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph);
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
const Sp_handler *sph)
{
if (!sphead)
return make_sp_head(thd, name, type);
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0),
stored_procedure_type_to_str(type));
return make_sp_head(thd, name, sph);
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
sp_head *make_sp_head_no_recursive(THD *thd,
DDL_options_st options, sp_name *name,
enum stored_procedure_type type)
const Sp_handler *sph)
{
if (add_create_options_with_check(options))
return NULL;
return make_sp_head_no_recursive(thd, name, type);
return make_sp_head_no_recursive(thd, name, sph);
}
bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name);

View File

@ -2937,13 +2937,13 @@ static int mysql_create_routine(THD *thd, LEX *lex)
{
if (check_routine_access(thd, ALTER_PROC_ACL, lex->sphead->m_db.str,
lex->sphead->m_name.str,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
Sp_handler::handler(lex->sql_command), 0))
return true;
}
const LEX_CSTRING *name= lex->sphead->name();
#ifdef HAVE_DLOPEN
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION)
{
udf_func *udf = find_udf(name->str, name->length);
@ -2959,7 +2959,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
return true;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!sp_create_routine(thd, lex->sphead->m_type, lex->sphead))
if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */
@ -3006,10 +3006,10 @@ static int mysql_create_routine(THD *thd, LEX *lex)
if (sp_automatic_privileges && !opt_noacl &&
check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
lex->sphead->m_db.str, name->str,
lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
Sp_handler::handler(lex->sql_command), 1))
{
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str,
lex->sql_command == SQLCOM_CREATE_PROCEDURE))
Sp_handler::handler(lex->sql_command)))
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
thd->clear_error();
@ -5353,16 +5353,16 @@ end_with_restore_list:
if (lex->type == TYPE_ENUM_PROCEDURE ||
lex->type == TYPE_ENUM_FUNCTION)
{
const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
lex->type);
uint grants= lex->all_privileges
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
: lex->grant;
if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, 0))
if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0))
goto error;
/* Conditionally writes to binlog */
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_routine_grant(thd, all_tables,
lex->type == TYPE_ENUM_PROCEDURE,
res= mysql_routine_grant(thd, all_tables, sph,
lex->users_list, grants,
lex->sql_command == SQLCOM_REVOKE, TRUE);
if (!res)
@ -5768,15 +5768,15 @@ end_with_restore_list:
goto error;
if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str,
lex->spname->m_name.str, TRUE, FALSE))
lex->spname->m_name.str, &sp_handler_procedure,
false))
goto error;
/*
By this moment all needed SPs should be in cache so no need to look
into DB.
*/
if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
&thd->sp_proc_cache, TRUE)))
if (!(sp= sp_handler_procedure.sp_find_routine(thd, lex->spname, true)))
{
/*
sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error.
@ -5821,13 +5821,9 @@ end_with_restore_list:
case SQLCOM_ALTER_FUNCTION:
{
int sp_result;
enum stored_procedure_type type;
type= (lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
lex->spname->m_name.str,
lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
lex->spname->m_name.str, sph, 0))
goto error;
/*
@ -5837,7 +5833,7 @@ end_with_restore_list:
already puts on CREATE FUNCTION.
*/
/* Conditionally writes to binlog */
sp_result= sp_update_routine(thd, type, lex->spname, &lex->sp_chistics);
sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
switch (sp_result)
{
case SP_OK:
@ -5899,19 +5895,17 @@ end_with_restore_list:
#endif
int sp_result;
enum stored_procedure_type type;
type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
const char *db= lex->spname->m_db.str;
const char *name= lex->spname->m_name.str;
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
Sp_handler::handler(lex->sql_command), 0))
goto error;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
sp_result= sp_drop_routine(thd, type, lex->spname);
sp_result= sph->sp_drop_routine(thd, lex->spname);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
@ -5935,7 +5929,7 @@ end_with_restore_list:
if (sp_result != SP_KEY_NOT_FOUND &&
sp_automatic_privileges && !opt_noacl &&
sp_revoke_privileges(thd, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE))
Sp_handler::handler(lex->sql_command)))
{
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_REVOKE_FAIL,
@ -5973,21 +5967,14 @@ end_with_restore_list:
break;
}
case SQLCOM_SHOW_CREATE_PROC:
{
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
goto error;
break;
}
case SQLCOM_SHOW_CREATE_FUNC:
{
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
goto error;
if (sph->sp_show_create_routine(thd, lex->spname))
goto error;
break;
}
case SQLCOM_SHOW_PROC_CODE:
@ -5995,13 +5982,11 @@ end_with_restore_list:
{
#ifndef DBUG_OFF
sp_head *sp;
stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp))
if (sph->sp_cache_routine(thd, lex->spname, false, &sp))
goto error;
if (!sp || sp->show_routine_code(thd))
{
@ -7061,7 +7046,7 @@ deny:
bool
check_routine_access(THD *thd, ulong want_access, const char *db,
const char *name,
bool is_proc, bool no_errors)
const Sp_handler *sph, bool no_errors)
{
TABLE_LIST tables[1];
@ -7090,7 +7075,7 @@ check_routine_access(THD *thd, ulong want_access, const char *db,
0, no_errors))
return TRUE;
return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
return check_grant_routine(thd, want_access, tables, sph, no_errors);
}
@ -7108,7 +7093,7 @@ check_routine_access(THD *thd, ulong want_access, const char *db,
*/
bool check_some_routine_access(THD *thd, const char *db, const char *name,
bool is_proc)
const Sp_handler *sph)
{
ulong save_priv;
/*
@ -7125,7 +7110,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) ||
(save_priv & SHOW_PROC_ACLS))
return FALSE;
return check_routine_level_acl(thd, db, name, is_proc);
return check_routine_level_acl(thd, db, name, sph);
}

View File

@ -152,9 +152,10 @@ bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables, bool no_errors);
bool check_routine_access(THD *thd,ulong want_access,const char *db,
const char *name,
bool is_proc, bool no_errors);
const Sp_handler *sph, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool check_some_routine_access(THD *thd, const char *db, const char *name,
const Sp_handler *sph);
bool check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number,
@ -166,7 +167,8 @@ inline bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables, bool no_errors)
{ return false; }
inline bool check_routine_access(THD *thd,ulong want_access, const char *db,
const char *name, bool is_proc, bool no_errors)
const char *name,
const Sp_handler *sph, bool no_errors)
{ return false; }
inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
@ -174,7 +176,8 @@ inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
return false;
}
inline bool check_some_routine_access(THD *thd, const char *db,
const char *name, bool is_proc)
const char *name,
const Sp_handler *sph)
{ return false; }
inline bool
check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,

View File

@ -2040,13 +2040,14 @@ static int mysql_test_show_binlogs(Prepared_statement *stmt)
TRUE error, error message is set in THD
*/
static int mysql_test_show_create_routine(Prepared_statement *stmt, int type)
static int mysql_test_show_create_routine(Prepared_statement *stmt,
const Sp_handler *sph)
{
DBUG_ENTER("mysql_test_show_binlogs");
THD *thd= stmt->thd;
List<Item> fields;
sp_head::show_create_routine_get_fields(thd, type, &fields);
sp_head::show_create_routine_get_fields(thd, sph, &fields);
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
@ -2436,14 +2437,14 @@ static bool check_prepared_statement(Prepared_statement *stmt)
break;
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE_PROC:
if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_PROCEDURE)) == 2)
if ((res= mysql_test_show_create_routine(stmt, &sp_handler_procedure)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
}
break;
case SQLCOM_SHOW_CREATE_FUNC:
if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_FUNCTION)) == 2)
if ((res= mysql_test_show_create_routine(stmt, &sp_handler_function)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);

View File

@ -3405,8 +3405,14 @@ void JOIN::exec_inner()
if (zero_result_cause)
{
if (select_lex->have_window_funcs())
if (select_lex->have_window_funcs() && send_row_on_empty_set())
{
/*
The query produces just one row but it has window functions.
The only way to compute the value of window function(s) is to
run the entire window function computation step (there is no shortcut).
*/
const_tables= table_count;
first_select= sub_select_postjoin_aggr;
}

View File

@ -5876,16 +5876,11 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
TABLE_SHARE share;
TABLE tbl;
CHARSET_INFO *cs= system_charset_info;
char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
definer_buff[DEFINER_LENGTH + 1];
String params(params_buff, sizeof(params_buff), cs);
String returns(returns_buff, sizeof(returns_buff), cs);
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
String definer(definer_buff, sizeof(definer_buff), cs);
LEX_CSTRING definer, params, returns= empty_clex_str;
LEX_CSTRING db, name;
char path[FN_REFLEN];
sp_head *sp;
stored_procedure_type routine_type;
const Sp_handler *sph;
bool free_sp_head;
bool error= 0;
DBUG_ENTER("store_schema_params");
@ -5894,48 +5889,44 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
(void) build_table_filename(path, sizeof(path), "", "", "", 0);
init_tmp_table_share(thd, &share, "", 0, "", path);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
routine_type= (stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
sph= Sp_handler::handler((stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
if (!sph)
sph= &sp_handler_procedure;
if (!full_access)
full_access= !strcmp(sp_user, definer.ptr());
full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
routine_type == TYPE_ENUM_PROCEDURE))
check_some_routine_access(thd, db.str, name.str, sph))
DBUG_RETURN(0);
params.length(0);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
&params);
returns.length(0);
if (routine_type == TYPE_ENUM_FUNCTION)
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
&returns);
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
routine_type,
returns.c_ptr_safe(),
params.c_ptr_safe(),
&free_sp_head);
proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params);
if (sph->type() == TYPE_ENUM_FUNCTION)
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
params, returns,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(),
&free_sp_head);
if (sp)
{
Field *field;
String tmp_string;
if (routine_type == TYPE_ENUM_FUNCTION)
LEX_CSTRING tmp_string;
if (sph->type() == TYPE_ENUM_FUNCTION)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[1]->store(db, cs);
table->field[2]->store(name, cs);
table->field[3]->store((longlong) 0, TRUE);
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
&tmp_string);
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
&tmp_string);
table->field[15]->store(tmp_string, cs);
field= sp->m_return_field_def.make_field(&share, thd->mem_root,
&empty_clex_str);
field->table= &tbl;
@ -5973,16 +5964,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[1]->store(db, cs);
table->field[2]->store(name, cs);
table->field[3]->store((longlong) i + 1, TRUE);
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
table->field[4]->set_notnull();
table->field[5]->store(spvar->name.str, spvar->name.length, cs);
table->field[5]->set_notnull();
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
&tmp_string);
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
&tmp_string);
table->field[15]->store(tmp_string, cs);
field= spvar->field_def.make_field(&share, thd->mem_root,
&spvar->name);
@ -6009,63 +6000,57 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
MYSQL_TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
definer_buff[DEFINER_LENGTH + 1],
returns_buff[MAX_FIELD_WIDTH];
const Sp_handler *sph;
LEX_CSTRING db, name, definer, returns= empty_clex_str;
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
String definer(definer_buff, sizeof(definer_buff), cs);
String returns(returns_buff, sizeof(returns_buff), cs);
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
sph= Sp_handler::handler((stored_procedure_type)
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
if (!sph)
sph= &sp_handler_procedure;
if (!full_access)
full_access= !strcmp(sp_user, definer.c_ptr_safe());
full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
val_int() == TYPE_ENUM_PROCEDURE))
check_some_routine_access(thd, db.str, name.str, sph))
return 0;
if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
TYPE_ENUM_PROCEDURE) ||
sph->type() == TYPE_ENUM_PROCEDURE) ||
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
TYPE_ENUM_FUNCTION) ||
sph->type() == TYPE_ENUM_FUNCTION) ||
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
sp_name.c_ptr_safe(), wild))
name.str, wild))
{
int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
table->field[3]->store(name, cs);
copy_field_as_string(table->field[0],
proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
table->field[1]->store(STRING_WITH_LEN("def"), cs);
table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
table->field[2]->store(db, cs);
copy_field_as_string(table->field[4],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
TYPE_ENUM_FUNCTION)
if (sph->type() == TYPE_ENUM_FUNCTION)
{
sp_head *sp;
bool free_sp_head;
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(),
TYPE_ENUM_FUNCTION,
returns.c_ptr_safe(),
"", &free_sp_head);
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sph->sp_load_for_information_schema(thd, proc_table,
db, name,
empty_clex_str /*params*/,
returns,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(),
&free_sp_head);
if (sp)
{
char path[FN_REFLEN];
@ -6115,7 +6100,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
copy_field_as_string(table->field[26],
proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
table->field[27]->store(definer.ptr(), definer.length(), cs);
table->field[27]->store(definer, cs);
copy_field_as_string(table->field[28],
proc_table->
field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);

View File

@ -471,6 +471,7 @@ public:
bool append(const char *s);
bool append(const LEX_STRING *ls) { return append(ls->str, ls->length); }
bool append(const LEX_CSTRING *ls) { return append(ls->str, ls->length); }
bool append(const LEX_CSTRING &ls) { return append(ls.str, ls.length); }
bool append(const char *s, uint32 arg_length);
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool append_ulonglong(ulonglong val);

View File

@ -2948,7 +2948,7 @@ ev_sql_stmt:
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
TYPE_ENUM_PROCEDURE))
&sp_handler_procedure))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
@ -3046,7 +3046,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
sp_add_used_routine(lex, thd, $2, TYPE_ENUM_PROCEDURE);
sp_handler_procedure.add_used_routine(lex, thd, $2);
}
opt_sp_cparam_list {}
;
@ -3880,20 +3880,9 @@ sp_proc_stmt_return:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (sp->m_type != TYPE_ENUM_FUNCTION)
my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
sp_instr_freturn *i;
i= new (thd->mem_root)
sp_instr_freturn(sp->instructions(), lex->spcont, $3,
sp->m_return_field_def.type_handler(), lex);
if (i == NULL || sp->add_instr(i))
MYSQL_YYABORT;
sp->m_flags|= sp_head::HAS_RETURN;
if (sp->restore_lex(thd))
if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
$3, lex) ||
sp->restore_lex(thd))
MYSQL_YYABORT;
}
;
@ -16607,7 +16596,7 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
if (!lex->make_sp_head(thd, $4, TYPE_ENUM_TRIGGER))
if (!lex->make_sp_head(thd, $4, &sp_handler_trigger))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
@ -16681,7 +16670,7 @@ sf_tail:
sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
TYPE_ENUM_FUNCTION))
&sp_handler_function))
MYSQL_YYABORT;
}
sp_parenthesized_fdparam_list
@ -16716,7 +16705,7 @@ sp_tail:
opt_if_not_exists sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
TYPE_ENUM_PROCEDURE))
&sp_handler_procedure))
MYSQL_YYABORT;
}
sp_parenthesized_pdparam_list

View File

@ -2389,7 +2389,7 @@ ev_sql_stmt:
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
TYPE_ENUM_PROCEDURE))
&sp_handler_procedure))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
@ -2492,7 +2492,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
sp_add_used_routine(lex, thd, $2, TYPE_ENUM_PROCEDURE);
sp_handler_procedure.add_used_routine(lex, thd, $2);
}
opt_sp_cparam_list {}
;
@ -3380,7 +3380,7 @@ sp_statement:
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
sp_add_used_routine(lex, thd, lex->spname, TYPE_ENUM_PROCEDURE);
sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
| ident_directly_assignable '.' ident
@ -3390,7 +3390,7 @@ sp_statement:
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
sp_add_used_routine(lex, thd, lex->spname, TYPE_ENUM_PROCEDURE);
sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
;
@ -3454,36 +3454,16 @@ sp_proc_stmt_return:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (sp->m_type != TYPE_ENUM_FUNCTION)
my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
sp_instr_freturn *i;
i= new (thd->mem_root)
sp_instr_freturn(sp->instructions(), lex->spcont, $3,
sp->m_return_field_def.type_handler(), lex);
if (i == NULL || sp->add_instr(i))
MYSQL_YYABORT;
sp->m_flags|= sp_head::HAS_RETURN;
if (sp->restore_lex(thd))
if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
$3, lex) ||
sp->restore_lex(thd))
MYSQL_YYABORT;
}
| RETURN_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (sp->m_type != TYPE_ENUM_PROCEDURE)
{
thd->parse_error();
MYSQL_YYABORT;
}
sp_instr_preturn *i;
i= new (thd->mem_root)
sp_instr_preturn(sp->instructions(), lex->spcont);
if (i == NULL || sp->add_instr(i))
if (sp->m_handler->add_instr_preturn(thd, sp, lex->spcont))
MYSQL_YYABORT;
}
;
@ -16844,7 +16824,7 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
if (!lex->make_sp_head(thd, $4, TYPE_ENUM_TRIGGER))
if (!lex->make_sp_head(thd, $4, &sp_handler_trigger))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
@ -16920,7 +16900,7 @@ sf_tail:
sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
TYPE_ENUM_FUNCTION))
&sp_handler_function))
MYSQL_YYABORT;
}
opt_sp_parenthesized_fdparam_list
@ -16958,7 +16938,7 @@ sp_tail:
opt_if_not_exists sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
TYPE_ENUM_PROCEDURE))
&sp_handler_procedure))
MYSQL_YYABORT;
}
opt_sp_parenthesized_pdparam_list

View File

@ -221,6 +221,8 @@ struct AUTHID
l->length= strxmov(buf, user.str, "@", host.str, NullS) - buf;
}
}
void parse(const char *str, size_t length);
bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};

View File

@ -2236,26 +2236,23 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
sp_head *sp = thd->lex->sphead;
sql_mode_t saved_mode= thd->variables.sql_mode;
String retstr(64);
LEX_CSTRING returns= empty_clex_str;
retstr.set_charset(system_charset_info);
log_query.set_charset(system_charset_info);
if (sp->m_type == TYPE_ENUM_FUNCTION)
if (sp->m_handler->type() == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
}
if (!show_create_sp(thd, &log_query,
sp->m_type,
(sp->m_explicit_name ? sp->m_db.str : NULL),
(sp->m_explicit_name ? sp->m_db.length : 0),
sp->m_name.str, sp->m_name.length,
sp->m_params.str, sp->m_params.length,
retstr.c_ptr(), retstr.length(),
sp->m_body.str, sp->m_body.length,
sp->chistics(), &(thd->lex->definer->user),
&(thd->lex->definer->host),
saved_mode))
if (!sp->m_handler->
show_create_sp(thd, &log_query,
sp->m_explicit_name ? sp->m_db : null_clex_str,
sp->m_name, sp->m_params, returns,
sp->m_body, sp->chistics(), thd->lex->definer[0],
saved_mode))
{
WSREP_WARN("SP create string failed: schema: %s, query: %s",
(thd->db ? thd->db : "(null)"), thd->query());