Merge remote-tracking branch 'origin/bb-10.2-ext' into 10.3
This commit is contained in:
commit
c431eafd62
@ -755,3 +755,21 @@ GRANT EXECUTE ON PROCEDURE `test`.`sp1` TO 'root'@'localhost'
|
|||||||
GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION
|
GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION
|
||||||
drop procedure sp1;
|
drop procedure sp1;
|
||||||
set password='';
|
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;
|
||||||
|
@ -2762,10 +2762,8 @@ CREATE TABLE t1 (i INT);
|
|||||||
INSERT INTO t1 VALUES (3), (1), (2);
|
INSERT INTO t1 VALUES (3), (1), (2);
|
||||||
SELECT i, ROW_NUMBER() OVER () FROM t1 WHERE 1 = 2;
|
SELECT i, ROW_NUMBER() OVER () FROM t1 WHERE 1 = 2;
|
||||||
i ROW_NUMBER() OVER ()
|
i ROW_NUMBER() OVER ()
|
||||||
NULL 1
|
|
||||||
SELECT i, COUNT(*) OVER () FROM t1 WHERE 1 = 2;
|
SELECT i, COUNT(*) OVER () FROM t1 WHERE 1 = 2;
|
||||||
i COUNT(*) OVER ()
|
i COUNT(*) OVER ()
|
||||||
NULL 1
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
# MDEV-12051: window function in query with implicit grouping
|
# 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
|
63 2
|
||||||
drop table t1;
|
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
|
# Start of 10.3 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -11,10 +11,6 @@ c1 c2
|
|||||||
4 manual_insert_2
|
4 manual_insert_2
|
||||||
11 should repeat 4 times [11-14]
|
11 should repeat 4 times [11-14]
|
||||||
12 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;
|
DELETE FROM t1;
|
||||||
EXECUTE populate_table;
|
EXECUTE populate_table;
|
||||||
INSERT INTO t1
|
INSERT INTO t1
|
||||||
|
@ -1023,3 +1023,30 @@ grant execute on procedure sp1 to current_user() identified by 'barfoo';
|
|||||||
show grants;
|
show grants;
|
||||||
drop procedure sp1;
|
drop procedure sp1;
|
||||||
set password='';
|
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;
|
||||||
|
@ -1924,6 +1924,36 @@ select sum(i) over (order by i), interval(sum(i) over (order by i), 10, 20)
|
|||||||
from t1;
|
from t1;
|
||||||
drop table 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 #
|
||||||
--echo # Start of 10.3 tests
|
--echo # Start of 10.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
19
sql/field.cc
19
sql/field.cc
@ -10773,3 +10773,22 @@ void Field::register_field_in_read_map()
|
|||||||
}
|
}
|
||||||
bitmap_set_bit(table->read_set, field_index);
|
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;
|
||||||
|
}
|
||||||
|
15
sql/field.h
15
sql/field.h
@ -839,6 +839,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual String *val_str(String*,String *)=0;
|
virtual String *val_str(String*,String *)=0;
|
||||||
String *val_int_as_str(String *val_buffer, bool unsigned_flag);
|
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);
|
fast_field_copier get_fast_field_copier(const Field *from);
|
||||||
/*
|
/*
|
||||||
str_needs_quotes() returns TRUE if the value returned by val_str() needs
|
str_needs_quotes() returns TRUE if the value returned by val_str() needs
|
||||||
|
@ -3424,7 +3424,7 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
|
|||||||
arg_count= item_list->elements;
|
arg_count= item_list->elements;
|
||||||
|
|
||||||
qname= new (thd->mem_root) sp_name(db, name, use_explicit_name);
|
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)
|
if (arg_count > 0)
|
||||||
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname,
|
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname,
|
||||||
|
@ -6265,8 +6265,7 @@ Item_func_sp::init_result_field(THD *thd)
|
|||||||
DBUG_ASSERT(m_sp == NULL);
|
DBUG_ASSERT(m_sp == NULL);
|
||||||
DBUG_ASSERT(sp_result_field == NULL);
|
DBUG_ASSERT(sp_result_field == NULL);
|
||||||
|
|
||||||
if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
|
if (!(m_sp= sp_handler_function.sp_find_routine(thd, m_name, true)))
|
||||||
&thd->sp_func_cache, TRUE)))
|
|
||||||
{
|
{
|
||||||
my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
|
my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
|
||||||
context->process_error(thd);
|
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_ENTER("Item_func_sp::sp_check_access");
|
||||||
DBUG_ASSERT(m_sp);
|
DBUG_ASSERT(m_sp);
|
||||||
if (check_routine_access(thd, EXECUTE_ACL,
|
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(TRUE);
|
||||||
|
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
@ -6541,7 +6541,8 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
|
|||||||
thd->security_ctx= context->security_ctx;
|
thd->security_ctx= context->security_ctx;
|
||||||
|
|
||||||
res= check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str,
|
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;
|
thd->security_ctx= save_security_ctx;
|
||||||
|
|
||||||
if (res)
|
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
|
Try to set and restore the security context to see whether it's valid
|
||||||
*/
|
*/
|
||||||
Security_context *save_secutiry_ctx;
|
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)
|
if (!res)
|
||||||
m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);
|
m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);
|
||||||
|
|
||||||
|
329
sql/sp.h
329
sql/sp.h
@ -17,7 +17,10 @@
|
|||||||
#ifndef _SP_H_
|
#ifndef _SP_H_
|
||||||
#define _SP_H_
|
#define _SP_H_
|
||||||
|
|
||||||
|
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||||
#include "sql_string.h" // LEX_STRING
|
#include "sql_string.h" // LEX_STRING
|
||||||
|
#include "sql_cmd.h"
|
||||||
|
#include "mdl.h"
|
||||||
|
|
||||||
class Field;
|
class Field;
|
||||||
class Open_tables_backup;
|
class Open_tables_backup;
|
||||||
@ -28,8 +31,10 @@ class Sroutine_hash_entry;
|
|||||||
class THD;
|
class THD;
|
||||||
class sp_cache;
|
class sp_cache;
|
||||||
class sp_head;
|
class sp_head;
|
||||||
class sp_name;
|
class sp_pcontext;
|
||||||
|
class Database_qualified_name;
|
||||||
struct st_sp_chistics;
|
struct st_sp_chistics;
|
||||||
|
class Stored_program_creation_ctx;
|
||||||
struct LEX;
|
struct LEX;
|
||||||
struct TABLE;
|
struct TABLE;
|
||||||
struct TABLE_LIST;
|
struct TABLE_LIST;
|
||||||
@ -49,19 +54,268 @@ enum stored_procedure_type
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline const char *
|
class Sp_handler
|
||||||
stored_procedure_type_to_str(enum stored_procedure_type type)
|
{
|
||||||
|
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 ¶ms,
|
||||||
|
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 ¶ms,
|
||||||
|
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 ¶ms,
|
||||||
|
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) {
|
switch (type) {
|
||||||
case TYPE_ENUM_PROCEDURE: return "PROCEDURE";
|
case TYPE_ENUM_PROCEDURE:
|
||||||
case TYPE_ENUM_FUNCTION: return "FUNCTION";
|
return &sp_handler_procedure;
|
||||||
case TYPE_ENUM_TRIGGER: return "TRIGGER";
|
case TYPE_ENUM_FUNCTION:
|
||||||
case TYPE_ENUM_PROXY: return "PROXY";
|
return &sp_handler_function;
|
||||||
|
case TYPE_ENUM_TRIGGER:
|
||||||
|
return &sp_handler_trigger;
|
||||||
|
case TYPE_ENUM_PROXY:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
DBUG_ASSERT(0);
|
return NULL;
|
||||||
return "UNKNOWN_STORED_";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
|
||||||
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
|
#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);
|
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
|
Structure that represents element in the set of stored routines
|
||||||
used by statement or routine.
|
used by statement or routine.
|
||||||
@ -185,14 +409,11 @@ public:
|
|||||||
changes.
|
changes.
|
||||||
*/
|
*/
|
||||||
ulong m_sp_cache_version;
|
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,
|
bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
|
||||||
const MDL_key *key, TABLE_LIST *belong_to_view);
|
const MDL_key *key, TABLE_LIST *belong_to_view);
|
||||||
void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
|
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);
|
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,
|
bool load_charset(MEM_ROOT *mem_root,
|
||||||
Field *field,
|
Field *field,
|
||||||
CHARSET_INFO *dflt_cs,
|
CHARSET_INFO *dflt_cs,
|
||||||
@ -231,17 +445,6 @@ bool load_collation(MEM_ROOT *mem_root,
|
|||||||
|
|
||||||
void sp_returns_type(THD *thd,
|
void sp_returns_type(THD *thd,
|
||||||
String &result,
|
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_ */
|
#endif /* _SP_H_ */
|
||||||
|
132
sql/sp_head.cc
132
sql/sp_head.cc
@ -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),
|
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
|
||||||
Database_qualified_name(&null_clex_str, &null_clex_str),
|
Database_qualified_name(&null_clex_str, &null_clex_str),
|
||||||
m_type(type),
|
m_handler(sph),
|
||||||
m_flags(0),
|
m_flags(0),
|
||||||
m_explicit_name(false),
|
m_explicit_name(false),
|
||||||
/*
|
/*
|
||||||
@ -610,7 +610,7 @@ sp_head::init(LEX *lex)
|
|||||||
|
|
||||||
|
|
||||||
void
|
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");
|
DBUG_ENTER("sp_head::init_sp_name");
|
||||||
|
|
||||||
@ -733,7 +733,7 @@ sp_head::~sp_head()
|
|||||||
|
|
||||||
Field *
|
Field *
|
||||||
sp_head::create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
|
sp_head::create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
|
||||||
TABLE *table)
|
TABLE *table) const
|
||||||
{
|
{
|
||||||
Field *field;
|
Field *field;
|
||||||
LEX_CSTRING name;
|
LEX_CSTRING name;
|
||||||
@ -960,30 +960,15 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
void Sp_handler_procedure::recursion_level_error(THD *thd,
|
||||||
Return appropriate error about recursion limit reaching
|
const sp_head *sp) const
|
||||||
|
|
||||||
@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)
|
|
||||||
{
|
{
|
||||||
if (m_type == TYPE_ENUM_PROCEDURE)
|
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
|
||||||
{
|
static_cast<int>(thd->variables.max_sp_recursion_depth),
|
||||||
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
|
sp->m_name.str);
|
||||||
static_cast<int>(thd->variables.max_sp_recursion_depth),
|
|
||||||
m_name.str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
my_error(ER_SP_NO_RECURSION, MYF(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Execute the routine. The main instruction jump loop is there.
|
Execute the routine. The main instruction jump loop is there.
|
||||||
Assume the parameters already set.
|
Assume the parameters already set.
|
||||||
@ -1391,7 +1376,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
|
|
||||||
@param thd thread handle
|
@param thd thread handle
|
||||||
@param sp stored routine to change the context for
|
@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
|
@param save_ctx pointer to an old security context
|
||||||
|
|
||||||
@todo
|
@todo
|
||||||
@ -1406,8 +1390,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
|
set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx)
|
||||||
Security_context **save_ctx)
|
|
||||||
{
|
{
|
||||||
*save_ctx= 0;
|
*save_ctx= 0;
|
||||||
if (sp->suid() != SP_IS_NOT_SUID &&
|
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 &&
|
if (*save_ctx &&
|
||||||
check_routine_access(thd, EXECUTE_ACL,
|
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);
|
sp->m_security_ctx.restore_security_context(thd, *save_ctx);
|
||||||
*save_ctx= 0;
|
*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.
|
so we can omit the security context switch for performance purposes.
|
||||||
|
|
||||||
@param thd
|
@param thd
|
||||||
@param sphead
|
|
||||||
@param is_proc
|
|
||||||
@param root_pctx
|
|
||||||
@param ret_value
|
@param ret_value
|
||||||
@retval NULL - error (access denided or EOM)
|
@retval NULL - error (access denided or EOM)
|
||||||
@retval !NULL - success (the invoker has rights to all %TYPE tables)
|
@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;
|
bool has_column_type_refs= m_flags & HAS_COLUMN_TYPE_REFS;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
Security_context *save_security_ctx;
|
Security_context *save_security_ctx;
|
||||||
if (has_column_type_refs &&
|
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;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
sp_rcontext *res= sp_rcontext::create(thd, m_pcont, ret_value,
|
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));
|
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
|
||||||
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
|
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);
|
thd->restore_active_arena(&call_arena, &backup_arena);
|
||||||
err_status= TRUE;
|
err_status= TRUE;
|
||||||
@ -1760,7 +1740,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
|||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
Security_context *save_security_ctx;
|
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;
|
err_status= TRUE;
|
||||||
goto err_with_cleanup;
|
goto err_with_cleanup;
|
||||||
@ -1904,7 +1884,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
if (! octx)
|
if (! octx)
|
||||||
{
|
{
|
||||||
/* Create a temporary old context. */
|
/* 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_PRINT("error", ("Could not create octx"));
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
@ -1919,7 +1899,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
thd->spcont->callers_arena= thd;
|
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. */
|
delete nctx; /* Delete nctx if it was init() that failed. */
|
||||||
thd->spcont= save_spcont;
|
thd->spcont= save_spcont;
|
||||||
@ -2042,7 +2022,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
Security_context *save_security_ctx= 0;
|
Security_context *save_security_ctx= 0;
|
||||||
if (!err_status)
|
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
|
#endif
|
||||||
|
|
||||||
if (!err_status)
|
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
|
void
|
||||||
sp_head::reset_thd_mem_root(THD *thd)
|
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)));
|
thd->security_ctx->priv_host)));
|
||||||
if (!*full_access)
|
if (!*full_access)
|
||||||
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
|
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;
|
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.
|
Collect metadata for SHOW CREATE statement for stored routines.
|
||||||
|
|
||||||
@param thd Thread context.
|
@param thd Thread context.
|
||||||
@param type Stored routine type
|
@param sph Stored routine handler
|
||||||
@param type Stored routine type
|
@param fields Item list to populate
|
||||||
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
|
|
||||||
|
|
||||||
@return Error status.
|
@return Error status.
|
||||||
@retval FALSE on success
|
@retval FALSE on success
|
||||||
@ -2572,13 +2530,11 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
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 ?
|
const char *col1_caption= sph->show_create_routine_col1_caption();
|
||||||
"Procedure" : "Function";
|
const char *col3_caption= sph->show_create_routine_col3_caption();
|
||||||
|
|
||||||
const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
|
|
||||||
"Create Procedure" : "Create Function";
|
|
||||||
|
|
||||||
MEM_ROOT *mem_root= thd->mem_root;
|
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.
|
Implement SHOW CREATE statement for stored routines.
|
||||||
|
|
||||||
@param thd Thread context.
|
@param thd Thread context.
|
||||||
@param type Stored routine type
|
@param sph Stored routine handler
|
||||||
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
|
|
||||||
|
|
||||||
@return Error status.
|
@return Error status.
|
||||||
@retval FALSE on success
|
@retval FALSE on success
|
||||||
@ -2634,13 +2589,10 @@ sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
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 ?
|
const char *col1_caption= sph->show_create_routine_col1_caption();
|
||||||
"Procedure" : "Function";
|
const char *col3_caption= sph->show_create_routine_col3_caption();
|
||||||
|
|
||||||
const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
|
|
||||||
"Create Procedure" : "Create Function";
|
|
||||||
|
|
||||||
bool err_status;
|
bool err_status;
|
||||||
|
|
||||||
@ -2655,9 +2607,6 @@ sp_head::show_create_routine(THD *thd, int type)
|
|||||||
DBUG_ENTER("sp_head::show_create_routine");
|
DBUG_ENTER("sp_head::show_create_routine");
|
||||||
DBUG_PRINT("info", ("routine %s", m_name.str));
|
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))
|
if (check_show_routine_access(thd, this, &full_access))
|
||||||
DBUG_RETURN(TRUE);
|
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".
|
Replace an instruction at position to "no operation".
|
||||||
|
|
||||||
|
@ -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
|
Item::Type
|
||||||
sp_map_item_type(enum enum_field_types type);
|
sp_map_item_type(enum enum_field_types type);
|
||||||
|
|
||||||
@ -173,7 +168,7 @@ public:
|
|||||||
HAS_COLUMN_TYPE_REFS= 8192
|
HAS_COLUMN_TYPE_REFS= 8192
|
||||||
};
|
};
|
||||||
|
|
||||||
stored_procedure_type m_type;
|
const Sp_handler *m_handler;
|
||||||
uint m_flags; // Boolean attributes of a stored routine
|
uint m_flags; // Boolean attributes of a stored routine
|
||||||
|
|
||||||
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
|
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
|
||||||
@ -220,7 +215,7 @@ public:
|
|||||||
m_sp_cache_version= version_arg;
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -317,7 +312,7 @@ public:
|
|||||||
static void
|
static void
|
||||||
operator delete(void *ptr, size_t size) throw ();
|
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
|
/// Initialize after we have reset mem_root
|
||||||
void
|
void
|
||||||
@ -325,7 +320,7 @@ public:
|
|||||||
|
|
||||||
/** Copy sp name from parser. */
|
/** Copy sp name from parser. */
|
||||||
void
|
void
|
||||||
init_sp_name(THD *thd, sp_name *spname);
|
init_sp_name(THD *thd, const sp_name *spname);
|
||||||
|
|
||||||
/** Set the body-definition start position. */
|
/** Set the body-definition start position. */
|
||||||
void
|
void
|
||||||
@ -350,10 +345,11 @@ public:
|
|||||||
execute_procedure(THD *thd, List<Item> *args);
|
execute_procedure(THD *thd, List<Item> *args);
|
||||||
|
|
||||||
static void
|
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
|
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; }
|
MEM_ROOT *get_main_mem_root() { return &main_mem_root; }
|
||||||
|
|
||||||
@ -376,6 +372,12 @@ public:
|
|||||||
spcont->last_label());
|
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);
|
Item *adjust_assignment_source(THD *thd, Item *val, Item *val2);
|
||||||
/**
|
/**
|
||||||
@param thd - the current thd
|
@param thd - the current thd
|
||||||
@ -622,7 +624,7 @@ public:
|
|||||||
char *create_string(THD *thd, ulong *lenp);
|
char *create_string(THD *thd, ulong *lenp);
|
||||||
|
|
||||||
Field *create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
|
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,
|
void set_info(longlong created, longlong modified,
|
||||||
const st_sp_chistics &chistics, sql_mode_t sql_mode);
|
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)
|
void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name)
|
||||||
{
|
{
|
||||||
m_definer.copy(mem_root, user_name, 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 add_mark_lead(uint ip, List<sp_instr> *leads);
|
||||||
|
|
||||||
void recursion_level_error(THD *thd);
|
|
||||||
|
|
||||||
inline sp_instr *
|
inline sp_instr *
|
||||||
get_instr(uint i)
|
get_instr(uint i)
|
||||||
{
|
{
|
||||||
@ -1859,8 +1864,7 @@ void
|
|||||||
sp_restore_security_context(THD *thd, Security_context *backup);
|
sp_restore_security_context(THD *thd, Security_context *backup);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
|
set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx);
|
||||||
Security_context **save_ctx);
|
|
||||||
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||||
|
|
||||||
TABLE_LIST *
|
TABLE_LIST *
|
||||||
|
173
sql/sql_acl.cc
173
sql/sql_acl.cc
@ -754,6 +754,19 @@ static int traverse_role_graph_down(ACL_USER_BASE *, void *,
|
|||||||
int (*) (ACL_USER_BASE *, void *),
|
int (*) (ACL_USER_BASE *, void *),
|
||||||
int (*) (ACL_USER_BASE *, ACL_ROLE *, 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
|
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 *
|
static GRANT_NAME *
|
||||||
routine_hash_search(const char *host, const char *ip, const char *db,
|
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*)
|
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);
|
host, ip, db, user, tname, exact, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5351,13 +5365,14 @@ table_error:
|
|||||||
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
|
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
|
||||||
TABLE *table, const LEX_USER &combo,
|
TABLE *table, const LEX_USER &combo,
|
||||||
const char *db, const char *routine_name,
|
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];
|
char grantor[USER_HOST_BUFF_SIZE];
|
||||||
int old_row_exists= 1;
|
int old_row_exists= 1;
|
||||||
int error=0;
|
int error=0;
|
||||||
ulong store_proc_rights;
|
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");
|
DBUG_ENTER("replace_routine_table");
|
||||||
|
|
||||||
if (revoke_grant && !grant_name->init_privs) // only inherited role privs
|
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[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
|
||||||
table->field[3]->store(routine_name,(uint) strlen(routine_name),
|
table->field[3]->store(routine_name,(uint) strlen(routine_name),
|
||||||
&my_charset_latin1);
|
&my_charset_latin1);
|
||||||
table->field[4]->store((longlong)(is_proc ?
|
table->field[4]->store((longlong) sph->type(), true);
|
||||||
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
|
|
||||||
TRUE);
|
|
||||||
store_record(table,record[1]); // store at pos 1
|
store_record(table,record[1]); // store at pos 1
|
||||||
|
|
||||||
if (table->file->ha_index_read_idx_map(table->record[0], 0,
|
if (table->file->ha_index_read_idx_map(table->record[0], 0,
|
||||||
@ -5503,6 +5516,23 @@ struct PRIVS_TO_MERGE
|
|||||||
const char *db, *name;
|
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)
|
static int init_role_for_merging(ACL_ROLE *role, void *context)
|
||||||
{
|
{
|
||||||
role->counter= 0;
|
role->counter= 0;
|
||||||
@ -6627,7 +6657,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
|
|||||||
|
|
||||||
@param thd Thread handle
|
@param thd Thread handle
|
||||||
@param table_list List of routines to give grant
|
@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 user_list List of users to give grant
|
||||||
@param rights Table level grant
|
@param rights Table level grant
|
||||||
@param revoke_grant Is this is a REVOKE command?
|
@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.
|
@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,
|
List <LEX_USER> &user_list, ulong rights,
|
||||||
bool revoke_grant, bool write_to_binlog)
|
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 (!revoke_grant)
|
||||||
{
|
{
|
||||||
if (sp_exist_routines(thd, table_list, is_proc))
|
if (sph->sp_exist_routines(thd, table_list))
|
||||||
DBUG_RETURN(TRUE);
|
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;
|
db_name= table_list->db;
|
||||||
table_name= table_list->table_name;
|
table_name= table_list->table_name;
|
||||||
grant_name= routine_hash_search(Str->host.str, NullS, db_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 (!grant_name || !grant_name->init_privs)
|
||||||
{
|
{
|
||||||
if (revoke_grant)
|
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,
|
Str->user.str, table_name,
|
||||||
rights, TRUE);
|
rights, TRUE);
|
||||||
if (!grant_name ||
|
if (!grant_name ||
|
||||||
my_hash_insert(is_proc ?
|
my_hash_insert(sph->get_priv_hash(), (uchar*) grant_name))
|
||||||
&proc_priv_hash : &func_priv_hash,(uchar*) grant_name))
|
|
||||||
{
|
{
|
||||||
result= TRUE;
|
result= TRUE;
|
||||||
continue;
|
continue;
|
||||||
@ -6724,7 +6754,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
|
|||||||
instead of TABLE directly. */
|
instead of TABLE directly. */
|
||||||
if (tables.procs_priv_table().no_such_table() ||
|
if (tables.procs_priv_table().no_such_table() ||
|
||||||
replace_routine_table(thd, grant_name, tables.procs_priv_table().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)
|
revoke_grant) != 0)
|
||||||
{
|
{
|
||||||
result= TRUE;
|
result= TRUE;
|
||||||
@ -6732,7 +6762,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
|
|||||||
}
|
}
|
||||||
if (Str->is_role())
|
if (Str->is_role())
|
||||||
propagate_role_grants(find_acl_role(Str->user.str),
|
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);
|
db_name, table_name);
|
||||||
}
|
}
|
||||||
thd->mem_root= old_root;
|
thd->mem_root= old_root;
|
||||||
@ -7341,16 +7371,10 @@ static bool grant_load(THD *thd,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (procs_priv.routine_type()->val_int() == TYPE_ENUM_PROCEDURE)
|
uint type= procs_priv.routine_type()->val_int();
|
||||||
{
|
const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
|
||||||
hash= &proc_priv_hash;
|
type);
|
||||||
}
|
if (!sph || !(hash= sph->get_priv_hash()))
|
||||||
else
|
|
||||||
if (procs_priv.routine_type()->val_int() == TYPE_ENUM_FUNCTION)
|
|
||||||
{
|
|
||||||
hash= &func_priv_hash;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
sql_print_warning("'procs_priv' entry '%s' "
|
sql_print_warning("'procs_priv' entry '%s' "
|
||||||
"ignored, bad routine type",
|
"ignored, bad routine type",
|
||||||
@ -8088,7 +8112,7 @@ bool check_grant_db(THD *thd, const char *db)
|
|||||||
thd Thread handler
|
thd Thread handler
|
||||||
want_access Bits of privileges user needs to have
|
want_access Bits of privileges user needs to have
|
||||||
procs List of routines to check. The user should have 'want_access'
|
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
|
no_errors If 0 then we write an error. The error is sent directly to
|
||||||
the client
|
the client
|
||||||
|
|
||||||
@ -8098,7 +8122,8 @@ bool check_grant_db(THD *thd, const char *db)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
bool check_grant_routine(THD *thd, ulong want_access,
|
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;
|
TABLE_LIST *table;
|
||||||
Security_context *sctx= thd->security_ctx;
|
Security_context *sctx= thd->security_ctx;
|
||||||
@ -8116,12 +8141,12 @@ bool check_grant_routine(THD *thd, ulong want_access,
|
|||||||
{
|
{
|
||||||
GRANT_NAME *grant_proc;
|
GRANT_NAME *grant_proc;
|
||||||
if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
|
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;
|
table->grant.privilege|= grant_proc->privs;
|
||||||
if (role[0]) /* current role set check */
|
if (role[0]) /* current role set check */
|
||||||
{
|
{
|
||||||
if ((grant_proc= routine_hash_search("", NULL, table->db, role,
|
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;
|
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 check_routine_level_acl(THD *thd, const char *db, const char *name,
|
||||||
bool is_proc)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
bool no_routine_acl= 1;
|
bool no_routine_acl= 1;
|
||||||
GRANT_NAME *grant_proc;
|
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,
|
if ((grant_proc= routine_hash_search(sctx->priv_host,
|
||||||
sctx->ip, db,
|
sctx->ip, db,
|
||||||
sctx->priv_user,
|
sctx->priv_user,
|
||||||
name, is_proc, 0)))
|
name, sph, 0)))
|
||||||
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
||||||
|
|
||||||
if (no_routine_acl && sctx->priv_role[0]) /* current set role check */
|
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("",
|
if ((grant_proc= routine_hash_search("",
|
||||||
NULL, db,
|
NULL, db,
|
||||||
sctx->priv_role,
|
sctx->priv_role,
|
||||||
name, is_proc, 0)))
|
name, sph, 0)))
|
||||||
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
||||||
}
|
}
|
||||||
mysql_rwlock_unlock(&LOCK_grant);
|
mysql_rwlock_unlock(&LOCK_grant);
|
||||||
@ -10503,6 +10528,45 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
|
|||||||
DBUG_RETURN(result);
|
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.
|
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)
|
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
|
||||||
{
|
{
|
||||||
uint counter, revoked, is_proc;
|
uint counter, revoked;
|
||||||
int result;
|
int result;
|
||||||
ACL_DB *acl_db;
|
ACL_DB *acl_db;
|
||||||
DBUG_ENTER("mysql_revoke_all");
|
DBUG_ENTER("mysql_revoke_all");
|
||||||
@ -10648,32 +10712,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
|
|||||||
} while (revoked);
|
} while (revoked);
|
||||||
|
|
||||||
/* Remove procedure access */
|
/* Remove procedure access */
|
||||||
for (is_proc=0; is_proc<2; is_proc++) do {
|
if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) ||
|
||||||
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
|
mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user))
|
||||||
for (counter= 0, revoked= 0 ; counter < hash->records ; )
|
result= -1;
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
ACL_USER_BASE *user_or_role;
|
ACL_USER_BASE *user_or_role;
|
||||||
/* remove role grants */
|
/* 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 sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
|
||||||
bool is_proc)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
uint counter, revoked;
|
uint counter, revoked;
|
||||||
int result;
|
int result;
|
||||||
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
|
HASH *hash= sph->get_priv_hash();
|
||||||
Silence_routine_definer_errors error_handler;
|
Silence_routine_definer_errors error_handler;
|
||||||
DBUG_ENTER("sp_revoke_privileges");
|
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,
|
if (replace_routine_table(thd, grant_proc,
|
||||||
tables.procs_priv_table().table(), lex_user,
|
tables.procs_priv_table().table(), lex_user,
|
||||||
grant_proc->db, grant_proc->tname,
|
grant_proc->db, grant_proc->tname,
|
||||||
is_proc, ~(ulong)0, 1) == 0)
|
sph, ~(ulong)0, 1) == 0)
|
||||||
{
|
{
|
||||||
revoked= 1;
|
revoked= 1;
|
||||||
continue;
|
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 thd The current thread.
|
||||||
@param sp_db
|
@param sp_db
|
||||||
@param sp_name
|
@param sp_name
|
||||||
@param is_proc
|
@param sph
|
||||||
|
|
||||||
@return
|
@return
|
||||||
@retval FALSE Success
|
@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 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;
|
Security_context *sctx= thd->security_ctx;
|
||||||
LEX_USER *combo;
|
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.
|
as all errors will be handled later.
|
||||||
*/
|
*/
|
||||||
thd->push_internal_handler(&error_handler);
|
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);
|
DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
|
||||||
thd->pop_internal_handler();
|
thd->pop_internal_handler();
|
||||||
DBUG_RETURN(result);
|
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 check_routine_level_acl(THD *thd, const char *db, const char *name,
|
||||||
bool is_proc)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
|
||||||
List <LEX_COLUMN> &column_list, ulong rights,
|
List <LEX_COLUMN> &column_list, ulong rights,
|
||||||
bool revoke);
|
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,
|
List <LEX_USER> &user_list, ulong rights,
|
||||||
bool revoke, bool write_to_binlog);
|
bool revoke, bool write_to_binlog);
|
||||||
bool grant_init();
|
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,
|
bool check_grant_all_columns(THD *thd, ulong want_access,
|
||||||
Field_iterator_table_ref *fields);
|
Field_iterator_table_ref *fields);
|
||||||
bool check_grant_routine(THD *thd, ulong want_access,
|
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_grant_db(THD *thd,const char *db);
|
||||||
bool check_global_access(THD *thd, ulong want_access, bool no_errors= false);
|
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,
|
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,
|
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
||||||
const char *db, const char *table);
|
const char *db, const char *table);
|
||||||
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
|
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 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 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);
|
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_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
|
||||||
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
|
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
|
||||||
|
@ -3127,7 +3127,7 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
|
|||||||
DEBUG_SYNC(thd, "after_shared_lock_pname");
|
DEBUG_SYNC(thd, "after_shared_lock_pname");
|
||||||
|
|
||||||
/* Ensures the routine is up-to-date and cached, if exists. */
|
/* 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);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
/* Remember the version of the routine in the parse tree. */
|
/* 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
|
Validating routine version is unnecessary, since CALL
|
||||||
does not affect the prepared statement prelocked list.
|
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);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) */
|
#endif /* !defined(MYSQL_CLIENT) */
|
||||||
|
@ -4507,10 +4507,16 @@ void st_select_lex::set_explain_type(bool on_the_fly)
|
|||||||
if (join)
|
if (join)
|
||||||
{
|
{
|
||||||
bool uses_cte= false;
|
bool uses_cte= false;
|
||||||
for (JOIN_TAB *tab= first_explain_order_tab(join); tab;
|
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS,
|
||||||
tab= next_explain_order_tab(join, tab))
|
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;
|
uses_cte= true;
|
||||||
break;
|
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)
|
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 &&
|
name->length == 3 &&
|
||||||
(!my_strcasecmp(system_charset_info, name->str, "NEW") ||
|
(!my_strcasecmp(system_charset_info, name->str, "NEW") ||
|
||||||
!my_strcasecmp(system_charset_info, name->str, "OLD"));
|
!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,
|
sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
|
||||||
enum stored_procedure_type type)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
|
|
||||||
/* Order is important here: new - reset - init */
|
/* 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->reset_thd_mem_root(thd);
|
||||||
sp->init(this);
|
sp->init(this);
|
||||||
@ -6121,7 +6127,7 @@ bool LEX::maybe_start_compound_statement(THD *thd)
|
|||||||
{
|
{
|
||||||
if (!sphead)
|
if (!sphead)
|
||||||
{
|
{
|
||||||
if (!make_sp_head(thd, NULL, TYPE_ENUM_PROCEDURE))
|
if (!make_sp_head(thd, NULL, &sp_handler_procedure))
|
||||||
return true;
|
return true;
|
||||||
sphead->set_suid(SP_IS_NOT_SUID);
|
sphead->set_suid(SP_IS_NOT_SUID);
|
||||||
sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());
|
sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());
|
||||||
|
@ -1287,6 +1287,7 @@ struct st_sp_chistics
|
|||||||
enum enum_sp_data_access daccess;
|
enum enum_sp_data_access daccess;
|
||||||
void init() { bzero(this, sizeof(*this)); }
|
void init() { bzero(this, sizeof(*this)); }
|
||||||
void set(const st_sp_chistics &other) { *this= other; }
|
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();
|
void set_stmt_init();
|
||||||
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name);
|
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name);
|
||||||
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2);
|
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2);
|
||||||
sp_head *make_sp_head(THD *thd, sp_name *name,
|
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph);
|
||||||
enum stored_procedure_type type);
|
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
|
||||||
sp_head *make_sp_head_no_recursive(THD *thd, sp_name *name,
|
const Sp_handler *sph)
|
||||||
enum stored_procedure_type type)
|
|
||||||
{
|
{
|
||||||
if (!sphead)
|
if (!sphead)
|
||||||
return make_sp_head(thd, name, type);
|
return make_sp_head(thd, name, sph);
|
||||||
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0),
|
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
|
||||||
stored_procedure_type_to_str(type));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sp_head *make_sp_head_no_recursive(THD *thd,
|
sp_head *make_sp_head_no_recursive(THD *thd,
|
||||||
DDL_options_st options, sp_name *name,
|
DDL_options_st options, sp_name *name,
|
||||||
enum stored_procedure_type type)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
if (add_create_options_with_check(options))
|
if (add_create_options_with_check(options))
|
||||||
return NULL;
|
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,
|
bool init_internal_variable(struct sys_var_with_base *variable,
|
||||||
const LEX_CSTRING *name);
|
const LEX_CSTRING *name);
|
||||||
|
@ -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,
|
if (check_routine_access(thd, ALTER_PROC_ACL, lex->sphead->m_db.str,
|
||||||
lex->sphead->m_name.str,
|
lex->sphead->m_name.str,
|
||||||
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
|
Sp_handler::handler(lex->sql_command), 0))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LEX_CSTRING *name= lex->sphead->name();
|
const LEX_CSTRING *name= lex->sphead->name();
|
||||||
#ifdef HAVE_DLOPEN
|
#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);
|
udf_func *udf = find_udf(name->str, name->length);
|
||||||
|
|
||||||
@ -2959,7 +2959,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
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
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
/* only add privileges if really neccessary */
|
/* 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 &&
|
if (sp_automatic_privileges && !opt_noacl &&
|
||||||
check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
|
check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
|
||||||
lex->sphead->m_db.str, name->str,
|
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,
|
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,
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
|
ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
|
||||||
thd->clear_error();
|
thd->clear_error();
|
||||||
@ -5353,16 +5353,16 @@ end_with_restore_list:
|
|||||||
if (lex->type == TYPE_ENUM_PROCEDURE ||
|
if (lex->type == TYPE_ENUM_PROCEDURE ||
|
||||||
lex->type == TYPE_ENUM_FUNCTION)
|
lex->type == TYPE_ENUM_FUNCTION)
|
||||||
{
|
{
|
||||||
|
const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
|
||||||
|
lex->type);
|
||||||
uint grants= lex->all_privileges
|
uint grants= lex->all_privileges
|
||||||
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
|
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
|
||||||
: lex->grant;
|
: lex->grant;
|
||||||
if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
|
if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0))
|
||||||
lex->type == TYPE_ENUM_PROCEDURE, 0))
|
|
||||||
goto error;
|
goto error;
|
||||||
/* Conditionally writes to binlog */
|
/* Conditionally writes to binlog */
|
||||||
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
||||||
res= mysql_routine_grant(thd, all_tables,
|
res= mysql_routine_grant(thd, all_tables, sph,
|
||||||
lex->type == TYPE_ENUM_PROCEDURE,
|
|
||||||
lex->users_list, grants,
|
lex->users_list, grants,
|
||||||
lex->sql_command == SQLCOM_REVOKE, TRUE);
|
lex->sql_command == SQLCOM_REVOKE, TRUE);
|
||||||
if (!res)
|
if (!res)
|
||||||
@ -5768,15 +5768,15 @@ end_with_restore_list:
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str,
|
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;
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
By this moment all needed SPs should be in cache so no need to look
|
By this moment all needed SPs should be in cache so no need to look
|
||||||
into DB.
|
into DB.
|
||||||
*/
|
*/
|
||||||
if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
|
if (!(sp= sp_handler_procedure.sp_find_routine(thd, lex->spname, true)))
|
||||||
&thd->sp_proc_cache, TRUE)))
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error.
|
sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error.
|
||||||
@ -5821,13 +5821,9 @@ end_with_restore_list:
|
|||||||
case SQLCOM_ALTER_FUNCTION:
|
case SQLCOM_ALTER_FUNCTION:
|
||||||
{
|
{
|
||||||
int sp_result;
|
int sp_result;
|
||||||
enum stored_procedure_type type;
|
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
|
||||||
type= (lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
|
|
||||||
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
|
|
||||||
|
|
||||||
if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
|
if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
|
||||||
lex->spname->m_name.str,
|
lex->spname->m_name.str, sph, 0))
|
||||||
lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5837,7 +5833,7 @@ end_with_restore_list:
|
|||||||
already puts on CREATE FUNCTION.
|
already puts on CREATE FUNCTION.
|
||||||
*/
|
*/
|
||||||
/* Conditionally writes to binlog */
|
/* 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)
|
switch (sp_result)
|
||||||
{
|
{
|
||||||
case SP_OK:
|
case SP_OK:
|
||||||
@ -5899,19 +5895,17 @@ end_with_restore_list:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sp_result;
|
int sp_result;
|
||||||
enum stored_procedure_type type;
|
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
|
||||||
type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
|
|
||||||
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
|
|
||||||
const char *db= lex->spname->m_db.str;
|
const char *db= lex->spname->m_db.str;
|
||||||
const char *name= lex->spname->m_name.str;
|
const char *name= lex->spname->m_name.str;
|
||||||
|
|
||||||
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
|
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;
|
goto error;
|
||||||
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
||||||
|
|
||||||
/* Conditionally writes to binlog */
|
/* 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
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
/*
|
/*
|
||||||
@ -5935,7 +5929,7 @@ end_with_restore_list:
|
|||||||
if (sp_result != SP_KEY_NOT_FOUND &&
|
if (sp_result != SP_KEY_NOT_FOUND &&
|
||||||
sp_automatic_privileges && !opt_noacl &&
|
sp_automatic_privileges && !opt_noacl &&
|
||||||
sp_revoke_privileges(thd, db, name,
|
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,
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_PROC_AUTO_REVOKE_FAIL,
|
ER_PROC_AUTO_REVOKE_FAIL,
|
||||||
@ -5973,21 +5967,14 @@ end_with_restore_list:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SQLCOM_SHOW_CREATE_PROC:
|
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:
|
case SQLCOM_SHOW_CREATE_FUNC:
|
||||||
{
|
{
|
||||||
|
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
|
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
|
if (sph->sp_show_create_routine(thd, lex->spname))
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SQLCOM_SHOW_PROC_CODE:
|
case SQLCOM_SHOW_PROC_CODE:
|
||||||
@ -5995,13 +5982,11 @@ end_with_restore_list:
|
|||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
|
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
|
||||||
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
|
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
|
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
|
||||||
#endif /* WITH_WSREP */
|
#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;
|
goto error;
|
||||||
if (!sp || sp->show_routine_code(thd))
|
if (!sp || sp->show_routine_code(thd))
|
||||||
{
|
{
|
||||||
@ -7061,7 +7046,7 @@ deny:
|
|||||||
bool
|
bool
|
||||||
check_routine_access(THD *thd, ulong want_access, const char *db,
|
check_routine_access(THD *thd, ulong want_access, const char *db,
|
||||||
const char *name,
|
const char *name,
|
||||||
bool is_proc, bool no_errors)
|
const Sp_handler *sph, bool no_errors)
|
||||||
{
|
{
|
||||||
TABLE_LIST tables[1];
|
TABLE_LIST tables[1];
|
||||||
|
|
||||||
@ -7090,7 +7075,7 @@ check_routine_access(THD *thd, ulong want_access, const char *db,
|
|||||||
0, no_errors))
|
0, no_errors))
|
||||||
return TRUE;
|
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 check_some_routine_access(THD *thd, const char *db, const char *name,
|
||||||
bool is_proc)
|
const Sp_handler *sph)
|
||||||
{
|
{
|
||||||
ulong save_priv;
|
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) ||
|
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) ||
|
||||||
(save_priv & SHOW_PROC_ACLS))
|
(save_priv & SHOW_PROC_ACLS))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return check_routine_level_acl(thd, db, name, is_proc);
|
return check_routine_level_acl(thd, db, name, sph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,9 +152,10 @@ bool check_single_table_access(THD *thd, ulong privilege,
|
|||||||
TABLE_LIST *tables, bool no_errors);
|
TABLE_LIST *tables, bool no_errors);
|
||||||
bool check_routine_access(THD *thd,ulong want_access,const char *db,
|
bool check_routine_access(THD *thd,ulong want_access,const char *db,
|
||||||
const char *name,
|
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_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 check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
||||||
bool any_combination_of_privileges_will_do,
|
bool any_combination_of_privileges_will_do,
|
||||||
uint number,
|
uint number,
|
||||||
@ -166,7 +167,8 @@ inline bool check_single_table_access(THD *thd, ulong privilege,
|
|||||||
TABLE_LIST *tables, bool no_errors)
|
TABLE_LIST *tables, bool no_errors)
|
||||||
{ return false; }
|
{ return false; }
|
||||||
inline bool check_routine_access(THD *thd,ulong want_access, const char *db,
|
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; }
|
{ return false; }
|
||||||
inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
inline bool check_some_routine_access(THD *thd, const char *db,
|
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; }
|
{ return false; }
|
||||||
inline bool
|
inline bool
|
||||||
check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
||||||
|
@ -2040,13 +2040,14 @@ static int mysql_test_show_binlogs(Prepared_statement *stmt)
|
|||||||
TRUE error, error message is set in THD
|
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");
|
DBUG_ENTER("mysql_test_show_binlogs");
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
List<Item> fields;
|
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));
|
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
|
||||||
}
|
}
|
||||||
@ -2436,14 +2437,14 @@ static bool check_prepared_statement(Prepared_statement *stmt)
|
|||||||
break;
|
break;
|
||||||
#endif /* EMBEDDED_LIBRARY */
|
#endif /* EMBEDDED_LIBRARY */
|
||||||
case SQLCOM_SHOW_CREATE_PROC:
|
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 */
|
/* Statement and field info has already been sent */
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SQLCOM_SHOW_CREATE_FUNC:
|
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 */
|
/* Statement and field info has already been sent */
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
@ -3405,8 +3405,14 @@ void JOIN::exec_inner()
|
|||||||
|
|
||||||
if (zero_result_cause)
|
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;
|
const_tables= table_count;
|
||||||
first_select= sub_select_postjoin_aggr;
|
first_select= sub_select_postjoin_aggr;
|
||||||
}
|
}
|
||||||
|
141
sql/sql_show.cc
141
sql/sql_show.cc
@ -5876,16 +5876,11 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
|
|||||||
TABLE_SHARE share;
|
TABLE_SHARE share;
|
||||||
TABLE tbl;
|
TABLE tbl;
|
||||||
CHARSET_INFO *cs= system_charset_info;
|
CHARSET_INFO *cs= system_charset_info;
|
||||||
char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
|
LEX_CSTRING definer, params, returns= empty_clex_str;
|
||||||
sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
|
LEX_CSTRING db, name;
|
||||||
definer_buff[DEFINER_LENGTH + 1];
|
char path[FN_REFLEN];
|
||||||
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);
|
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
stored_procedure_type routine_type;
|
const Sp_handler *sph;
|
||||||
bool free_sp_head;
|
bool free_sp_head;
|
||||||
bool error= 0;
|
bool error= 0;
|
||||||
DBUG_ENTER("store_schema_params");
|
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);
|
(void) build_table_filename(path, sizeof(path), "", "", "", 0);
|
||||||
init_tmp_table_share(thd, &share, "", 0, "", path);
|
init_tmp_table_share(thd, &share, "", 0, "", path);
|
||||||
|
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
|
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
|
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
|
||||||
get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
|
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
|
||||||
routine_type= (stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
|
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)
|
if (!full_access)
|
||||||
full_access= !strcmp(sp_user, definer.ptr());
|
full_access= !strcmp(sp_user, definer.str);
|
||||||
if (!full_access &&
|
if (!full_access &&
|
||||||
check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
|
check_some_routine_access(thd, db.str, name.str, sph))
|
||||||
routine_type == TYPE_ENUM_PROCEDURE))
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
params.length(0);
|
proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
|
¶ms);
|
||||||
¶ms);
|
if (sph->type() == TYPE_ENUM_FUNCTION)
|
||||||
returns.length(0);
|
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
|
||||||
if (routine_type == TYPE_ENUM_FUNCTION)
|
&returns);
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
|
sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
|
||||||
&returns);
|
params, returns,
|
||||||
|
(ulong) proc_table->
|
||||||
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
|
field[MYSQL_PROC_FIELD_SQL_MODE]->
|
||||||
(ulong) proc_table->
|
val_int(),
|
||||||
field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
|
&free_sp_head);
|
||||||
routine_type,
|
|
||||||
returns.c_ptr_safe(),
|
|
||||||
params.c_ptr_safe(),
|
|
||||||
&free_sp_head);
|
|
||||||
|
|
||||||
if (sp)
|
if (sp)
|
||||||
{
|
{
|
||||||
Field *field;
|
Field *field;
|
||||||
String tmp_string;
|
LEX_CSTRING tmp_string;
|
||||||
if (routine_type == TYPE_ENUM_FUNCTION)
|
if (sph->type() == TYPE_ENUM_FUNCTION)
|
||||||
{
|
{
|
||||||
restore_record(table, s->default_values);
|
restore_record(table, s->default_values);
|
||||||
table->field[0]->store(STRING_WITH_LEN("def"), cs);
|
table->field[0]->store(STRING_WITH_LEN("def"), cs);
|
||||||
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
|
table->field[1]->store(db, cs);
|
||||||
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
|
table->field[2]->store(name, cs);
|
||||||
table->field[3]->store((longlong) 0, TRUE);
|
table->field[3]->store((longlong) 0, TRUE);
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
|
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
|
||||||
&tmp_string);
|
&tmp_string);
|
||||||
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
table->field[15]->store(tmp_string, cs);
|
||||||
field= sp->m_return_field_def.make_field(&share, thd->mem_root,
|
field= sp->m_return_field_def.make_field(&share, thd->mem_root,
|
||||||
&empty_clex_str);
|
&empty_clex_str);
|
||||||
field->table= &tbl;
|
field->table= &tbl;
|
||||||
@ -5973,16 +5964,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
|
|||||||
|
|
||||||
restore_record(table, s->default_values);
|
restore_record(table, s->default_values);
|
||||||
table->field[0]->store(STRING_WITH_LEN("def"), cs);
|
table->field[0]->store(STRING_WITH_LEN("def"), cs);
|
||||||
table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
|
table->field[1]->store(db, cs);
|
||||||
table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
|
table->field[2]->store(name, cs);
|
||||||
table->field[3]->store((longlong) i + 1, TRUE);
|
table->field[3]->store((longlong) i + 1, TRUE);
|
||||||
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
|
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
|
||||||
table->field[4]->set_notnull();
|
table->field[4]->set_notnull();
|
||||||
table->field[5]->store(spvar->name.str, spvar->name.length, cs);
|
table->field[5]->store(spvar->name.str, spvar->name.length, cs);
|
||||||
table->field[5]->set_notnull();
|
table->field[5]->set_notnull();
|
||||||
get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
|
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
|
||||||
&tmp_string);
|
&tmp_string);
|
||||||
table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
table->field[15]->store(tmp_string, cs);
|
||||||
|
|
||||||
field= spvar->field_def.make_field(&share, thd->mem_root,
|
field= spvar->field_def.make_field(&share, thd->mem_root,
|
||||||
&spvar->name);
|
&spvar->name);
|
||||||
@ -6009,63 +6000,57 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
|
|||||||
MYSQL_TIME time;
|
MYSQL_TIME time;
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
CHARSET_INFO *cs= system_charset_info;
|
CHARSET_INFO *cs= system_charset_info;
|
||||||
char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
|
const Sp_handler *sph;
|
||||||
definer_buff[DEFINER_LENGTH + 1],
|
LEX_CSTRING db, name, definer, returns= empty_clex_str;
|
||||||
returns_buff[MAX_FIELD_WIDTH];
|
|
||||||
|
|
||||||
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
|
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
|
||||||
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
|
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
|
||||||
String definer(definer_buff, sizeof(definer_buff), cs);
|
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
|
||||||
String returns(returns_buff, sizeof(returns_buff), cs);
|
sph= Sp_handler::handler((stored_procedure_type)
|
||||||
|
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
|
||||||
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
|
if (!sph)
|
||||||
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
|
sph= &sp_handler_procedure;
|
||||||
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
|
|
||||||
|
|
||||||
if (!full_access)
|
if (!full_access)
|
||||||
full_access= !strcmp(sp_user, definer.c_ptr_safe());
|
full_access= !strcmp(sp_user, definer.str);
|
||||||
if (!full_access &&
|
if (!full_access &&
|
||||||
check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
|
check_some_routine_access(thd, db.str, name.str, sph))
|
||||||
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
|
|
||||||
val_int() == TYPE_ENUM_PROCEDURE))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
|
if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
|
||||||
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
|
sph->type() == TYPE_ENUM_PROCEDURE) ||
|
||||||
TYPE_ENUM_PROCEDURE) ||
|
|
||||||
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
|
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
|
||||||
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
|
sph->type() == TYPE_ENUM_FUNCTION) ||
|
||||||
TYPE_ENUM_FUNCTION) ||
|
|
||||||
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
|
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
|
||||||
{
|
{
|
||||||
restore_record(table, s->default_values);
|
restore_record(table, s->default_values);
|
||||||
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
|
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();
|
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],
|
copy_field_as_string(table->field[0],
|
||||||
proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
|
proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
|
||||||
table->field[1]->store(STRING_WITH_LEN("def"), cs);
|
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],
|
copy_field_as_string(table->field[4],
|
||||||
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
|
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
|
||||||
|
|
||||||
if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
|
if (sph->type() == TYPE_ENUM_FUNCTION)
|
||||||
TYPE_ENUM_FUNCTION)
|
|
||||||
{
|
{
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
bool free_sp_head;
|
bool free_sp_head;
|
||||||
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
|
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
|
||||||
sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
|
&returns);
|
||||||
(ulong) proc_table->
|
sp= sph->sp_load_for_information_schema(thd, proc_table,
|
||||||
field[MYSQL_PROC_FIELD_SQL_MODE]->
|
db, name,
|
||||||
val_int(),
|
empty_clex_str /*params*/,
|
||||||
TYPE_ENUM_FUNCTION,
|
returns,
|
||||||
returns.c_ptr_safe(),
|
(ulong) proc_table->
|
||||||
"", &free_sp_head);
|
field[MYSQL_PROC_FIELD_SQL_MODE]->
|
||||||
|
val_int(),
|
||||||
|
&free_sp_head);
|
||||||
if (sp)
|
if (sp)
|
||||||
{
|
{
|
||||||
char path[FN_REFLEN];
|
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],
|
copy_field_as_string(table->field[26],
|
||||||
proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
|
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],
|
copy_field_as_string(table->field[28],
|
||||||
proc_table->
|
proc_table->
|
||||||
field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
|
field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
|
||||||
|
@ -471,6 +471,7 @@ public:
|
|||||||
bool append(const char *s);
|
bool append(const char *s);
|
||||||
bool append(const LEX_STRING *ls) { return append(ls->str, ls->length); }
|
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 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);
|
||||||
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
|
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
|
||||||
bool append_ulonglong(ulonglong val);
|
bool append_ulonglong(ulonglong val);
|
||||||
|
@ -2948,7 +2948,7 @@ ev_sql_stmt:
|
|||||||
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
|
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
|
||||||
|
|
||||||
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
|
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
|
||||||
TYPE_ENUM_PROCEDURE))
|
&sp_handler_procedure))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
|
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
|
||||||
@ -3046,7 +3046,7 @@ call:
|
|||||||
lex->sql_command= SQLCOM_CALL;
|
lex->sql_command= SQLCOM_CALL;
|
||||||
lex->spname= $2;
|
lex->spname= $2;
|
||||||
lex->value_list.empty();
|
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 {}
|
opt_sp_cparam_list {}
|
||||||
;
|
;
|
||||||
@ -3880,20 +3880,9 @@ sp_proc_stmt_return:
|
|||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp= lex->sphead;
|
sp_head *sp= lex->sphead;
|
||||||
|
if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
|
||||||
if (sp->m_type != TYPE_ENUM_FUNCTION)
|
$3, lex) ||
|
||||||
my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
|
sp->restore_lex(thd))
|
||||||
|
|
||||||
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))
|
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -16607,7 +16596,7 @@ trigger_tail:
|
|||||||
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
|
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
|
||||||
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
|
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;
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
|
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
|
||||||
@ -16681,7 +16670,7 @@ sf_tail:
|
|||||||
sp_name
|
sp_name
|
||||||
{
|
{
|
||||||
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
||||||
TYPE_ENUM_FUNCTION))
|
&sp_handler_function))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
sp_parenthesized_fdparam_list
|
sp_parenthesized_fdparam_list
|
||||||
@ -16716,7 +16705,7 @@ sp_tail:
|
|||||||
opt_if_not_exists sp_name
|
opt_if_not_exists sp_name
|
||||||
{
|
{
|
||||||
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
||||||
TYPE_ENUM_PROCEDURE))
|
&sp_handler_procedure))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
sp_parenthesized_pdparam_list
|
sp_parenthesized_pdparam_list
|
||||||
|
@ -2389,7 +2389,7 @@ ev_sql_stmt:
|
|||||||
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
|
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
|
||||||
|
|
||||||
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
|
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
|
||||||
TYPE_ENUM_PROCEDURE))
|
&sp_handler_procedure))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
|
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
|
||||||
@ -2492,7 +2492,7 @@ call:
|
|||||||
lex->sql_command= SQLCOM_CALL;
|
lex->sql_command= SQLCOM_CALL;
|
||||||
lex->spname= $2;
|
lex->spname= $2;
|
||||||
lex->value_list.empty();
|
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 {}
|
opt_sp_cparam_list {}
|
||||||
;
|
;
|
||||||
@ -3380,7 +3380,7 @@ sp_statement:
|
|||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
lex->sql_command= SQLCOM_CALL;
|
lex->sql_command= SQLCOM_CALL;
|
||||||
lex->value_list.empty();
|
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
|
opt_sp_cparam_list
|
||||||
| ident_directly_assignable '.' ident
|
| ident_directly_assignable '.' ident
|
||||||
@ -3390,7 +3390,7 @@ sp_statement:
|
|||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
lex->sql_command= SQLCOM_CALL;
|
lex->sql_command= SQLCOM_CALL;
|
||||||
lex->value_list.empty();
|
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
|
opt_sp_cparam_list
|
||||||
;
|
;
|
||||||
@ -3454,36 +3454,16 @@ sp_proc_stmt_return:
|
|||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp= lex->sphead;
|
sp_head *sp= lex->sphead;
|
||||||
|
if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
|
||||||
if (sp->m_type != TYPE_ENUM_FUNCTION)
|
$3, lex) ||
|
||||||
my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
|
sp->restore_lex(thd))
|
||||||
|
|
||||||
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))
|
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| RETURN_SYM
|
| RETURN_SYM
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp= lex->sphead;
|
sp_head *sp= lex->sphead;
|
||||||
|
if (sp->m_handler->add_instr_preturn(thd, sp, lex->spcont))
|
||||||
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))
|
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -16844,7 +16824,7 @@ trigger_tail:
|
|||||||
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
|
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
|
||||||
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
|
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;
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
|
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
|
||||||
@ -16920,7 +16900,7 @@ sf_tail:
|
|||||||
sp_name
|
sp_name
|
||||||
{
|
{
|
||||||
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
||||||
TYPE_ENUM_FUNCTION))
|
&sp_handler_function))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
opt_sp_parenthesized_fdparam_list
|
opt_sp_parenthesized_fdparam_list
|
||||||
@ -16958,7 +16938,7 @@ sp_tail:
|
|||||||
opt_if_not_exists sp_name
|
opt_if_not_exists sp_name
|
||||||
{
|
{
|
||||||
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
|
||||||
TYPE_ENUM_PROCEDURE))
|
&sp_handler_procedure))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
opt_sp_parenthesized_pdparam_list
|
opt_sp_parenthesized_pdparam_list
|
||||||
|
@ -221,6 +221,8 @@ struct AUTHID
|
|||||||
l->length= strxmov(buf, user.str, "@", host.str, NullS) - buf;
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2236,26 +2236,23 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
|
|||||||
sp_head *sp = thd->lex->sphead;
|
sp_head *sp = thd->lex->sphead;
|
||||||
sql_mode_t saved_mode= thd->variables.sql_mode;
|
sql_mode_t saved_mode= thd->variables.sql_mode;
|
||||||
String retstr(64);
|
String retstr(64);
|
||||||
|
LEX_CSTRING returns= empty_clex_str;
|
||||||
retstr.set_charset(system_charset_info);
|
retstr.set_charset(system_charset_info);
|
||||||
|
|
||||||
log_query.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);
|
sp_returns_type(thd, retstr, sp);
|
||||||
|
returns= retstr.lex_cstring();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!show_create_sp(thd, &log_query,
|
if (!sp->m_handler->
|
||||||
sp->m_type,
|
show_create_sp(thd, &log_query,
|
||||||
(sp->m_explicit_name ? sp->m_db.str : NULL),
|
sp->m_explicit_name ? sp->m_db : null_clex_str,
|
||||||
(sp->m_explicit_name ? sp->m_db.length : 0),
|
sp->m_name, sp->m_params, returns,
|
||||||
sp->m_name.str, sp->m_name.length,
|
sp->m_body, sp->chistics(), thd->lex->definer[0],
|
||||||
sp->m_params.str, sp->m_params.length,
|
saved_mode))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
WSREP_WARN("SP create string failed: schema: %s, query: %s",
|
WSREP_WARN("SP create string failed: schema: %s, query: %s",
|
||||||
(thd->db ? thd->db : "(null)"), thd->query());
|
(thd->db ? thd->db : "(null)"), thd->query());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user