MDEV-13415 Wrap the code in sp.cc into a class Sp_handler

This commit is contained in:
Alexander Barkov 2017-07-31 23:00:02 +04:00
parent 4937474f86
commit c9218ff439
18 changed files with 751 additions and 574 deletions

View File

@ -3424,7 +3424,7 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
arg_count= item_list->elements; 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,

View File

@ -6264,8 +6264,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);
@ -6514,7 +6513,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);
@ -6540,7 +6540,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)
@ -6583,7 +6584,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);

398
sql/sp.cc
View File

@ -20,6 +20,7 @@
#include "unireg.h" #include "unireg.h"
#include "sp.h" #include "sp.h"
#include "sql_base.h" // close_thread_tables #include "sql_base.h" // close_thread_tables
#include "sql_lex.h" // empty_clex_str
#include "sql_parse.h" // parse_sql #include "sql_parse.h" // parse_sql
#include "key.h" // key_copy #include "key.h" // key_copy
#include "sql_show.h" // append_definer, append_identifier #include "sql_show.h" // append_definer, append_identifier
@ -34,20 +35,59 @@
#include <my_user.h> #include <my_user.h>
/* Used in error handling only */
#define SP_TYPE_STRING(type) stored_procedure_type_to_str(type) sp_cache **Sp_handler_procedure::get_cache(THD *thd) const
{
static int return &thd->sp_proc_cache;
db_load_routine(THD *thd, stored_procedure_type type, const sp_name *name, }
sp_head **sphp,
sql_mode_t sql_mode, sp_cache **Sp_handler_function::get_cache(THD *thd) const
const LEX_CSTRING &params, {
const LEX_CSTRING &returns, return &thd->sp_func_cache;
const LEX_CSTRING &body, }
const st_sp_chistics &chistics,
const AUTHID &definer, ulong Sp_handler_procedure::recursion_depth(THD *thd) const
longlong created, longlong modified, {
Stored_program_creation_ctx *creation_ctx); return thd->variables.max_sp_recursion_depth;
}
bool Sp_handler::add_instr_freturn(THD *thd, sp_head *sp,
sp_pcontext *spcont,
Item *item, LEX *lex) const
{
my_error(ER_SP_BADRETURN, MYF(0));
return true;
}
bool Sp_handler::add_instr_preturn(THD *thd, sp_head *sp,
sp_pcontext *spcont) const
{
thd->parse_error();
return true;
}
bool Sp_handler_function::add_instr_freturn(THD *thd, sp_head *sp,
sp_pcontext *spcont,
Item *item, LEX *lex) const
{
return sp->add_instr_freturn(thd, spcont, item, lex);
}
bool Sp_handler_procedure::add_instr_preturn(THD *thd, sp_head *sp,
sp_pcontext *spcont) const
{
return sp->add_instr_preturn(thd, spcont);
}
Sp_handler_procedure sp_handler_procedure;
Sp_handler_function sp_handler_function;
Sp_handler_trigger sp_handler_trigger;
static const static const
TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] = TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
@ -178,7 +218,7 @@ class Stored_routine_creation_ctx : public Stored_program_creation_ctx,
{ {
public: public:
static Stored_routine_creation_ctx * static Stored_routine_creation_ctx *
load_from_db(THD *thd, const sp_name *name, TABLE *proc_tbl); load_from_db(THD *thd, const Database_qualified_name *name, TABLE *proc_tbl);
public: public:
virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root) virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
@ -267,8 +307,8 @@ bool load_collation(MEM_ROOT *mem_root,
Stored_routine_creation_ctx * Stored_routine_creation_ctx *
Stored_routine_creation_ctx::load_from_db(THD *thd, Stored_routine_creation_ctx::load_from_db(THD *thd,
const sp_name *name, const Database_qualified_name *name,
TABLE *proc_tbl) TABLE *proc_tbl)
{ {
/* Load character set/collation attributes. */ /* Load character set/collation attributes. */
@ -463,7 +503,6 @@ static TABLE *open_proc_table_for_update(THD *thd)
Find row in open mysql.proc table representing stored routine. Find row in open mysql.proc table representing stored routine.
@param thd Thread context @param thd Thread context
@param type Type of routine to find (function or procedure)
@param name Name of routine @param name Name of routine
@param table TABLE object for open mysql.proc table. @param table TABLE object for open mysql.proc table.
@ -473,15 +512,16 @@ static TABLE *open_proc_table_for_update(THD *thd)
SP_KEY_NOT_FOUND No routine with given name SP_KEY_NOT_FOUND No routine with given name
*/ */
static int int
db_find_routine_aux(THD *thd, stored_procedure_type type, Sp_handler::db_find_routine_aux(THD *thd,
const Database_qualified_name *name, const Database_qualified_name *name,
TABLE *table) TABLE *table) const
{ {
uchar key[MAX_KEY_LENGTH]; // db, name, optional key length type uchar key[MAX_KEY_LENGTH]; // db, name, optional key length type
DBUG_ENTER("db_find_routine_aux"); DBUG_ENTER("db_find_routine_aux");
DBUG_PRINT("enter", ("type: %d name: %.*s", DBUG_PRINT("enter", ("type: %s name: %.*s",
type, (int) name->m_name.length, name->m_name.str)); type_str(),
(int) name->m_name.length, name->m_name.str));
/* /*
Create key to find row. We have to use field->store() to be able to Create key to find row. We have to use field->store() to be able to
@ -494,7 +534,7 @@ db_find_routine_aux(THD *thd, stored_procedure_type type,
DBUG_RETURN(SP_KEY_NOT_FOUND); DBUG_RETURN(SP_KEY_NOT_FOUND);
table->field[0]->store(name->m_db, &my_charset_bin); table->field[0]->store(name->m_db, &my_charset_bin);
table->field[1]->store(name->m_name, &my_charset_bin); table->field[1]->store(name->m_name, &my_charset_bin);
table->field[2]->store((longlong) type, TRUE); table->field[2]->store((longlong) type(), true);
key_copy(key, table->record[0], table->key_info, key_copy(key, table->record[0], table->key_info,
table->key_info->key_length); table->key_info->key_length);
@ -568,7 +608,6 @@ bool AUTHID::read_from_mysql_proc_row(THD *thd, TABLE *table)
sp_head object for it. sp_head object for it.
@param thd Thread context @param thd Thread context
@param type Type of routine (TYPE_ENUM_PROCEDURE/...)
@param name Name of routine @param name Name of routine
@param sphp Out parameter in which pointer to created sp_head @param sphp Out parameter in which pointer to created sp_head
object is returned (0 in case of error). object is returned (0 in case of error).
@ -583,9 +622,10 @@ bool AUTHID::read_from_mysql_proc_row(THD *thd, TABLE *table)
non-0 Error (may be one of special codes like SP_KEY_NOT_FOUND) non-0 Error (may be one of special codes like SP_KEY_NOT_FOUND)
*/ */
static int int
db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name, Sp_handler::db_find_routine(THD *thd,
sp_head **sphp) const Database_qualified_name *name,
sp_head **sphp) const
{ {
TABLE *table; TABLE *table;
LEX_CSTRING params, returns, body; LEX_CSTRING params, returns, body;
@ -600,8 +640,9 @@ db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
AUTHID definer; AUTHID definer;
DBUG_ENTER("db_find_routine"); DBUG_ENTER("db_find_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s", DBUG_PRINT("enter", ("type: %s name: %.*s",
type, (int) name->m_name.length, name->m_name.str)); type_str(),
(int) name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors *sphp= 0; // In case of errors
if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup))) if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
@ -610,7 +651,7 @@ db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
/* Reset sql_mode during data dictionary operations. */ /* Reset sql_mode during data dictionary operations. */
thd->variables.sql_mode= 0; thd->variables.sql_mode= 0;
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) if ((ret= db_find_routine_aux(thd, name, table)) != SP_OK)
goto done; goto done;
if (table->s->fields < MYSQL_PROC_FIELD_COUNT) if (table->s->fields < MYSQL_PROC_FIELD_COUNT)
@ -628,7 +669,7 @@ db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root, table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params); &params);
if (type == TYPE_ENUM_PROCEDURE) if (type() == TYPE_ENUM_PROCEDURE)
returns= empty_clex_str; returns= empty_clex_str;
else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root, else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns)) &returns))
@ -654,7 +695,7 @@ db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
close_system_tables(thd, &open_tables_state_backup); close_system_tables(thd, &open_tables_state_backup);
table= 0; table= 0;
ret= db_load_routine(thd, type, name, sphp, ret= db_load_routine(thd, name, sphp,
sql_mode, params, returns, body, chistics, definer, sql_mode, params, returns, body, chistics, definer,
created, modified, creation_ctx); created, modified, creation_ctx);
done: done:
@ -797,17 +838,17 @@ Bad_db_error_handler::handle_condition(THD *thd,
} }
static int int
db_load_routine(THD *thd, stored_procedure_type type, Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
const sp_name *name, sp_head **sphp, sp_head **sphp,
sql_mode_t sql_mode, sql_mode_t sql_mode,
const LEX_CSTRING &params, const LEX_CSTRING &params,
const LEX_CSTRING &returns, const LEX_CSTRING &returns,
const LEX_CSTRING &body, const LEX_CSTRING &body,
const st_sp_chistics &chistics, const st_sp_chistics &chistics,
const AUTHID &definer, const AUTHID &definer,
longlong created, longlong modified, longlong created, longlong modified,
Stored_program_creation_ctx *creation_ctx) Stored_program_creation_ctx *creation_ctx) const
{ {
LEX *old_lex= thd->lex, newlex; LEX *old_lex= thd->lex, newlex;
String defstr; String defstr;
@ -833,10 +874,9 @@ db_load_routine(THD *thd, stored_procedure_type type,
*/ */
if (!show_create_sp(thd, &defstr, if (!show_create_sp(thd, &defstr,
type, null_clex_str, name->m_name,
null_clex_str, name->m_name, params, returns, body,
params, returns, body, chistics, definer, sql_mode))
chistics, definer, sql_mode))
{ {
ret= SP_INTERNAL_ERROR; ret= SP_INTERNAL_ERROR;
goto end; goto end;
@ -911,7 +951,7 @@ end:
void void
sp_returns_type(THD *thd, String &result, sp_head *sp) sp_returns_type(THD *thd, String &result, const sp_head *sp)
{ {
TABLE table; TABLE table;
TABLE_SHARE share; TABLE_SHARE share;
@ -947,7 +987,6 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
and invalidates the stored-routine cache. and invalidates the stored-routine cache.
@param thd Thread context. @param thd Thread context.
@param type Stored routine type (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name. @param name Stored routine name.
@param table A pointer to the opened mysql.proc table @param table A pointer to the opened mysql.proc table
@ -955,9 +994,10 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
@return SP_OK on success, or SP_DELETE_ROW_FAILED on error. @return SP_OK on success, or SP_DELETE_ROW_FAILED on error.
used to indicate about errors. used to indicate about errors.
*/ */
static int int
sp_drop_routine_internal(THD *thd, stored_procedure_type type, Sp_handler::sp_drop_routine_internal(THD *thd,
const Database_qualified_name *name, TABLE *table) const Database_qualified_name *name,
TABLE *table) const
{ {
DBUG_ENTER("sp_drop_routine_internal"); DBUG_ENTER("sp_drop_routine_internal");
@ -974,10 +1014,9 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
local cache. local cache.
*/ */
sp_head *sp; sp_head *sp;
sp_cache **spc= (type == TYPE_ENUM_FUNCTION ? sp_cache **spc= get_cache(thd);
&thd->sp_func_cache : &thd->sp_proc_cache); DBUG_ASSERT(spc);
sp= sp_cache_lookup(spc, name); if ((sp= sp_cache_lookup(spc, name)))
if (sp)
sp_cache_flush_obsolete(spc, &sp); sp_cache_flush_obsolete(spc, &sp);
DBUG_RETURN(SP_OK); DBUG_RETURN(SP_OK);
} }
@ -990,8 +1029,6 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
the mysql.proc. the mysql.proc.
@param thd Thread context. @param thd Thread context.
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION).
@param sp Stored routine object to store. @param sp Stored routine object to store.
@note Opens and closes the thread tables. Therefore assumes @note Opens and closes the thread tables. Therefore assumes
@ -1008,7 +1045,7 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
*/ */
bool bool
sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp) Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
bool ret= TRUE; bool ret= TRUE;
@ -1016,8 +1053,6 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
char definer_buf[USER_HOST_BUFF_SIZE]; char definer_buf[USER_HOST_BUFF_SIZE];
LEX_CSTRING definer; LEX_CSTRING definer;
sql_mode_t saved_mode= thd->variables.sql_mode; sql_mode_t saved_mode= thd->variables.sql_mode;
MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
MDL_key::FUNCTION : MDL_key::PROCEDURE;
CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str); CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
@ -1025,16 +1060,15 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
bool store_failed= FALSE; bool store_failed= FALSE;
DBUG_ENTER("sp_create_routine"); DBUG_ENTER("sp_create_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s", (int) type, DBUG_PRINT("enter", ("type: %s name: %.*s",
type_str(),
(int) sp->m_name.length, (int) sp->m_name.length,
sp->m_name.str)); sp->m_name.str));
MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
LEX_CSTRING returns= empty_clex_str; LEX_CSTRING returns= empty_clex_str;
String retstr(64); String retstr(64);
retstr.set_charset(system_charset_info); retstr.set_charset(system_charset_info);
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
/* Grab an exclusive MDL lock. */ /* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, sp->m_db.str, sp->m_name.str)) if (lock_object_name(thd, mdl_type, sp->m_db.str, sp->m_name.str))
{ {
@ -1062,17 +1096,17 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (!(table= open_proc_table_for_update(thd))) if (!(table= open_proc_table_for_update(thd)))
{ {
my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(type),sp->m_name.str); my_error(ER_SP_STORE_FAILED, MYF(0), type_str(), sp->m_name.str);
goto done; goto done;
} }
else else
{ {
/* Checking if the routine already exists */ /* Checking if the routine already exists */
if (db_find_routine_aux(thd, type, sp, table) == SP_OK) if (db_find_routine_aux(thd, sp, table) == SP_OK)
{ {
if (lex->create_info.or_replace()) if (lex->create_info.or_replace())
{ {
if ((ret= sp_drop_routine_internal(thd, type, sp, table))) if ((ret= sp_drop_routine_internal(thd, sp, table)))
goto done; goto done;
} }
else if (lex->create_info.if_not_exists()) else if (lex->create_info.if_not_exists())
@ -1080,13 +1114,12 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_SP_ALREADY_EXISTS, ER_SP_ALREADY_EXISTS,
ER_THD(thd, ER_SP_ALREADY_EXISTS), ER_THD(thd, ER_SP_ALREADY_EXISTS),
SP_TYPE_STRING(type), type_str(), sp->m_name.str);
sp->m_name.str);
ret= FALSE; ret= FALSE;
// Setting retstr as it is used for logging. // Setting retstr as it is used for logging.
if (sp->m_type == TYPE_ENUM_FUNCTION) if (type() == TYPE_ENUM_FUNCTION)
{ {
sp_returns_type(thd, retstr, sp); sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring(); returns= retstr.lex_cstring();
@ -1095,8 +1128,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
} }
else else
{ {
my_error(ER_SP_ALREADY_EXISTS, MYF(0), my_error(ER_SP_ALREADY_EXISTS, MYF(0), type_str(), sp->m_name.str);
SP_TYPE_STRING(type), sp->m_name.str);
goto done; goto done;
} }
} }
@ -1108,8 +1140,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (table->s->fields < MYSQL_PROC_FIELD_COUNT) if (table->s->fields < MYSQL_PROC_FIELD_COUNT)
{ {
my_error(ER_SP_STORE_FAILED, MYF(0), my_error(ER_SP_STORE_FAILED, MYF(0), type_str(), sp->m_name.str);
SP_TYPE_STRING(type), sp->m_name.str);
goto done; goto done;
} }
@ -1137,7 +1168,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
store_failed= store_failed || store_failed= store_failed ||
table->field[MYSQL_PROC_MYSQL_TYPE]-> table->field[MYSQL_PROC_MYSQL_TYPE]->
store((longlong)type, TRUE); store((longlong) type(), true);
store_failed= store_failed || store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
@ -1165,7 +1196,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
store(sp->m_params, system_charset_info); store(sp->m_params, system_charset_info);
if (sp->m_type == TYPE_ENUM_FUNCTION) if (type() == TYPE_ENUM_FUNCTION)
{ {
sp_returns_type(thd, retstr, sp); sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring(); returns= retstr.lex_cstring();
@ -1197,7 +1228,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
store(sp->comment(), system_charset_info); store(sp->comment(), system_charset_info);
} }
if ((sp->m_type == TYPE_ENUM_FUNCTION) && if (type() == TYPE_ENUM_FUNCTION &&
!trust_function_creators && mysql_bin_log.is_open()) !trust_function_creators && mysql_bin_log.is_open())
{ {
if (!sp->detistic()) if (!sp->detistic())
@ -1255,8 +1286,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (table->file->ha_write_row(table->record[0])) if (table->file->ha_write_row(table->record[0]))
{ {
my_error(ER_SP_ALREADY_EXISTS, MYF(0), my_error(ER_SP_ALREADY_EXISTS, MYF(0), type_str(), sp->m_name.str);
SP_TYPE_STRING(type), sp->m_name.str);
goto done; goto done;
} }
/* Make change permanent and avoid 'table is marked as crashed' errors */ /* Make change permanent and avoid 'table is marked as crashed' errors */
@ -1274,7 +1304,6 @@ log:
log_query.set_charset(system_charset_info); log_query.set_charset(system_charset_info);
if (!show_create_sp(thd, &log_query, if (!show_create_sp(thd, &log_query,
sp->m_type,
sp->m_explicit_name ? sp->m_db : null_clex_str, sp->m_explicit_name ? sp->m_db : null_clex_str,
sp->m_name, sp->m_name,
sp->m_params, returns, sp->m_body, sp->m_params, returns, sp->m_body,
@ -1314,8 +1343,6 @@ done:
from the mysql.proc table and invalidates the stored-routine cache. from the mysql.proc table and invalidates the stored-routine cache.
@param thd Thread context. @param thd Thread context.
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name. @param name Stored routine name.
@return Error code. SP_OK is returned on success. Other SP_ constants are @return Error code. SP_OK is returned on success. Other SP_ constants are
@ -1323,18 +1350,16 @@ done:
*/ */
int int
sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name) Sp_handler::sp_drop_routine(THD *thd,
const Database_qualified_name *name) const
{ {
TABLE *table; TABLE *table;
int ret; int ret;
MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_drop_routine"); DBUG_ENTER("sp_drop_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s", DBUG_PRINT("enter", ("type: %s name: %.*s",
type, (int) name->m_name.length, name->m_name.str)); type_str(),
(int) name->m_name.length, name->m_name.str));
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
type == TYPE_ENUM_FUNCTION);
/* Grab an exclusive MDL lock. */ /* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str)) if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
@ -1343,8 +1368,8 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name)
if (!(table= open_proc_table_for_update(thd))) if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED); DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK)
ret= sp_drop_routine_internal(thd, type, name, table); ret= sp_drop_routine_internal(thd, name, table);
if (ret == SP_OK && if (ret == SP_OK &&
write_bin_log(thd, TRUE, thd->query(), thd->query_length())) write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
@ -1367,8 +1392,6 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name)
successful update, the cache is invalidated. successful update, the cache is invalidated.
@param thd Thread context. @param thd Thread context.
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name. @param name Stored routine name.
@param chistics New values of stored routine attributes to write. @param chistics New values of stored routine attributes to write.
@ -1377,20 +1400,16 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name)
*/ */
int int
sp_update_routine(THD *thd, stored_procedure_type type, const sp_name *name, Sp_handler::sp_update_routine(THD *thd, const Database_qualified_name *name,
const st_sp_chistics *chistics) const st_sp_chistics *chistics) const
{ {
TABLE *table; TABLE *table;
int ret; int ret;
MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_update_routine"); DBUG_ENTER("sp_update_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s", DBUG_PRINT("enter", ("type: %s name: %.*s",
(int) type, type_str(),
(int) name->m_name.length, name->m_name.str)); (int) name->m_name.length, name->m_name.str));
MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
/* Grab an exclusive MDL lock. */ /* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str)) if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
@ -1399,9 +1418,9 @@ sp_update_routine(THD *thd, stored_procedure_type type, const sp_name *name,
if (!(table= open_proc_table_for_update(thd))) if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED); DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK)
{ {
if (type == TYPE_ENUM_FUNCTION && ! trust_function_creators && if (type() == TYPE_ENUM_FUNCTION && ! trust_function_creators &&
mysql_bin_log.is_open() && mysql_bin_log.is_open() &&
(chistics->daccess == SP_CONTAINS_SQL || (chistics->daccess == SP_CONTAINS_SQL ||
chistics->daccess == SP_MODIFIES_SQL_DATA)) chistics->daccess == SP_MODIFIES_SQL_DATA))
@ -1650,8 +1669,6 @@ err:
calls sp_head::show_create_routine() for the object. calls sp_head::show_create_routine() for the object.
@param thd Thread context. @param thd Thread context.
@param type Stored routine type
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name. @param name Stored routine name.
@return Error status. @return Error status.
@ -1660,19 +1677,16 @@ err:
*/ */
bool bool
sp_show_create_routine(THD *thd, Sp_handler::sp_show_create_routine(THD *thd,
stored_procedure_type type, const sp_name *name) const Database_qualified_name *name) const
{ {
sp_head *sp; sp_head *sp;
DBUG_ENTER("sp_show_create_routine"); DBUG_ENTER("sp_show_create_routine");
DBUG_PRINT("enter", ("name: %.*s", DBUG_PRINT("enter", ("type: %s name: %.*s",
type_str(),
(int) name->m_name.length, (int) name->m_name.length,
name->m_name.str)); name->m_name.str));
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
/* /*
@todo: Consider using prelocking for this code as well. Currently @todo: Consider using prelocking for this code as well. Currently
SHOW CREATE PROCEDURE/FUNCTION is a dirty read of the data SHOW CREATE PROCEDURE/FUNCTION is a dirty read of the data
@ -1680,17 +1694,16 @@ sp_show_create_routine(THD *thd,
It is "safe" to do as long as it doesn't affect the results It is "safe" to do as long as it doesn't affect the results
of the binary log or the query cache, which currently it does not. of the binary log or the query cache, which currently it does not.
*/ */
if (sp_cache_routine(thd, type, name, FALSE, &sp)) if (sp_cache_routine(thd, name, false, &sp))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (sp == NULL || sp->show_create_routine(thd, type)) if (sp == NULL || sp->show_create_routine(thd, this))
{ {
/* /*
If we have insufficient privileges, pretend the routine If we have insufficient privileges, pretend the routine
does not exist. does not exist.
*/ */
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), stored_procedure_type_to_str(type), my_error(ER_SP_DOES_NOT_EXIST, MYF(0), type_str(), name->m_name.str);
name->m_name.str);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
@ -1703,7 +1716,6 @@ sp_show_create_routine(THD *thd,
stored procedures cache and looking into mysql.proc if needed. stored procedures cache and looking into mysql.proc if needed.
@param thd thread context @param thd thread context
@param type type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE)
@param name name of procedure @param name name of procedure
@param cp hash to look routine in @param cp hash to look routine in
@param cache_only if true perform cache-only lookup @param cache_only if true perform cache-only lookup
@ -1716,18 +1728,16 @@ sp_show_create_routine(THD *thd,
*/ */
sp_head * sp_head *
sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name, Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
sp_cache **cp, bool cache_only) bool cache_only) const
{ {
sp_cache **cp= get_cache(thd);
sp_head *sp; sp_head *sp;
ulong depth= (type == TYPE_ENUM_PROCEDURE ?
thd->variables.max_sp_recursion_depth :
0);
DBUG_ENTER("sp_find_routine"); DBUG_ENTER("sp_find_routine");
DBUG_PRINT("enter", ("name: %.*s.%.*s type: %d cache only %d", DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d",
(int) name->m_db.length, name->m_db.str, (int) name->m_db.length, name->m_db.str,
(int) name->m_name.length, name->m_name.str, (int) name->m_name.length, name->m_name.str,
type, cache_only)); type_str(), cache_only));
if ((sp= sp_cache_lookup(cp, name))) if ((sp= sp_cache_lookup(cp, name)))
{ {
@ -1750,9 +1760,9 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
sp->m_first_free_instance->m_recursion_level, sp->m_first_free_instance->m_recursion_level,
sp->m_first_free_instance->m_flags)); sp->m_first_free_instance->m_flags));
DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED));
if (sp->m_first_free_instance->m_recursion_level > depth) if (sp->m_first_free_instance->m_recursion_level > recursion_depth(thd))
{ {
sp->recursion_level_error(thd); recursion_level_error(thd, sp);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
DBUG_RETURN(sp->m_first_free_instance); DBUG_RETURN(sp->m_first_free_instance);
@ -1764,18 +1774,18 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
*/ */
level= sp->m_last_cached_sp->m_recursion_level + 1; level= sp->m_last_cached_sp->m_recursion_level + 1;
if (level > depth) if (level > recursion_depth(thd))
{ {
sp->recursion_level_error(thd); recursion_level_error(thd, sp);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
if (type == TYPE_ENUM_FUNCTION) if (type() == TYPE_ENUM_FUNCTION)
{ {
sp_returns_type(thd, retstr, sp); sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring(); returns= retstr.lex_cstring();
} }
if (db_load_routine(thd, type, name, &new_sp, if (db_load_routine(thd, name, &new_sp,
sp->m_sql_mode, sp->m_params, returns, sp->m_sql_mode, sp->m_params, returns,
sp->m_body, sp->chistics(), sp->m_body, sp->chistics(),
sp->m_definer, sp->m_definer,
@ -1795,7 +1805,7 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
} }
if (!cache_only) if (!cache_only)
{ {
if (db_find_routine(thd, type, name, &sp) == SP_OK) if (db_find_routine(thd, name, &sp) == SP_OK)
{ {
sp_cache_insert(cp, sp); sp_cache_insert(cp, sp);
DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x", DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x",
@ -1813,8 +1823,6 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
@param thd Thread handler @param thd Thread handler
@param routines List of needles in the hay stack @param routines List of needles in the hay stack
@param is_proc Indicates whether routines in the list are procedures
or functions.
@return @return
@retval FALSE Found. @retval FALSE Found.
@ -1822,7 +1830,7 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
*/ */
bool bool
sp_exist_routines(THD *thd, TABLE_LIST *routines, bool is_proc) Sp_handler::sp_exist_routines(THD *thd, TABLE_LIST *routines) const
{ {
TABLE_LIST *routine; TABLE_LIST *routine;
bool sp_object_found; bool sp_object_found;
@ -1836,12 +1844,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool is_proc)
thd->make_lex_string(&lex_name, routine->table_name, thd->make_lex_string(&lex_name, routine->table_name,
strlen(routine->table_name)); strlen(routine->table_name));
name= new sp_name(&lex_db, &lex_name, true); name= new sp_name(&lex_db, &lex_name, true);
sp_object_found= is_proc ? sp_find_routine(thd, TYPE_ENUM_PROCEDURE, sp_object_found= sp_find_routine(thd, name, false) != NULL;
name, &thd->sp_proc_cache,
FALSE) != NULL :
sp_find_routine(thd, TYPE_ENUM_FUNCTION,
name, &thd->sp_func_cache,
FALSE) != NULL;
thd->get_stmt_da()->clear_warning_info(thd->query_id); thd->get_stmt_da()->clear_warning_info(thd->query_id);
if (! sp_object_found) if (! sp_object_found)
{ {
@ -1932,20 +1935,18 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
@param arena Arena in which memory for new element of the set @param arena Arena in which memory for new element of the set
will be allocated will be allocated
@param rt Routine name @param rt Routine name
@param rt_type Routine type (one of TYPE_ENUM_PROCEDURE/...)
@note @note
Will also add element to end of 'Query_tables_list::sroutines_list' list Will also add element to end of 'Query_tables_list::sroutines_list' list
(and will take into account that this is an explicitly used routine). (and will take into account that this is an explicitly used routine).
*/ */
void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, void Sp_handler::add_used_routine(Query_tables_list *prelocking_ctx,
const sp_name *rt, enum stored_procedure_type rt_type) Query_arena *arena,
const Database_qualified_name *rt) const
{ {
MDL_key key((rt_type == TYPE_ENUM_FUNCTION) ? MDL_key::FUNCTION : MDL_key key(get_mdl_type(), rt->m_db.str, rt->m_name.str);
MDL_key::PROCEDURE, (void) sp_add_used_routine(prelocking_ctx, arena, &key, 0);
rt->m_db.str, rt->m_name.str);
(void)sp_add_used_routine(prelocking_ctx, arena, &key, 0);
prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next; prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next;
prelocking_ctx->sroutines_list_own_elements= prelocking_ctx->sroutines_list_own_elements=
prelocking_ctx->sroutines_list.elements; prelocking_ctx->sroutines_list.elements;
@ -2072,24 +2073,24 @@ void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
prelocking until 'sp_name' is eradicated as a class. prelocking until 'sp_name' is eradicated as a class.
*/ */
int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt, int Sroutine_hash_entry::sp_cache_routine(THD *thd,
bool lookup_only, sp_head **sp) bool lookup_only,
sp_head **sp) const
{ {
char qname_buff[NAME_LEN*2+1+1]; char qname_buff[NAME_LEN*2+1+1];
sp_name name(&rt->mdl_request.key, qname_buff); sp_name name(&mdl_request.key, qname_buff);
MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace(); MDL_key::enum_mdl_namespace mdl_type= mdl_request.key.mdl_namespace();
stored_procedure_type type= ((mdl_type == MDL_key::FUNCTION) ? const Sp_handler *sph= Sp_handler::handler(mdl_type);
TYPE_ENUM_FUNCTION : TYPE_ENUM_PROCEDURE); DBUG_ASSERT(sph);
/* /*
Check that we have an MDL lock on this routine, unless it's a top-level Check that we have an MDL lock on this routine, unless it's a top-level
CALL. The assert below should be unambiguous: the first element CALL. The assert below should be unambiguous: the first element
in sroutines_list has an MDL lock unless it's a top-level call, or a in sroutines_list has an MDL lock unless it's a top-level call, or a
trigger, but triggers can't occur here (see the preceding assert). trigger, but triggers can't occur here (see the preceding assert).
*/ */
DBUG_ASSERT(rt->mdl_request.ticket || rt == thd->lex->sroutines_list.first); DBUG_ASSERT(mdl_request.ticket || this == thd->lex->sroutines_list.first);
return sp_cache_routine(thd, type, &name, lookup_only, sp); return sph->sp_cache_routine(thd, &name, lookup_only, sp);
} }
@ -2100,7 +2101,6 @@ int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
loading. loading.
@param[in] thd Thread context. @param[in] thd Thread context.
@param[in] type Type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE).
@param[in] name Name of routine. @param[in] name Name of routine.
@param[in] lookup_only Only check that the routine is in the cache. @param[in] lookup_only Only check that the routine is in the cache.
If it's not, don't try to load. If it is present, If it's not, don't try to load. If it is present,
@ -2113,17 +2113,17 @@ int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
@retval non-0 Error while loading routine from mysql,proc table. @retval non-0 Error while loading routine from mysql,proc table.
*/ */
int sp_cache_routine(THD *thd, enum stored_procedure_type type, int Sp_handler::sp_cache_routine(THD *thd,
const sp_name *name, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) bool lookup_only,
sp_head **sp) const
{ {
int ret= 0; int ret= 0;
sp_cache **spc= (type == TYPE_ENUM_FUNCTION ? sp_cache **spc= get_cache(thd);
&thd->sp_func_cache : &thd->sp_proc_cache);
DBUG_ENTER("sp_cache_routine"); DBUG_ENTER("sp_cache_routine");
DBUG_ASSERT(type == TYPE_ENUM_FUNCTION || type == TYPE_ENUM_PROCEDURE); DBUG_ASSERT(spc);
*sp= sp_cache_lookup(spc, name); *sp= sp_cache_lookup(spc, name);
@ -2137,7 +2137,7 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type,
DBUG_RETURN(SP_OK); DBUG_RETURN(SP_OK);
} }
switch ((ret= db_find_routine(thd, type, name, sp))) switch ((ret= db_find_routine(thd, name, sp)))
{ {
case SP_OK: case SP_OK:
sp_cache_insert(spc, *sp); sp_cache_insert(spc, *sp);
@ -2179,16 +2179,15 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type,
Returns TRUE on success, FALSE on (alloc) failure. Returns TRUE on success, FALSE on (alloc) failure.
*/ */
bool bool
show_create_sp(THD *thd, String *buf, Sp_handler::show_create_sp(THD *thd, String *buf,
stored_procedure_type type, const LEX_CSTRING &db,
const LEX_CSTRING &db, const LEX_CSTRING &name,
const LEX_CSTRING &name, const LEX_CSTRING &params,
const LEX_CSTRING &params, const LEX_CSTRING &returns,
const LEX_CSTRING &returns, const LEX_CSTRING &body,
const LEX_CSTRING &body, const st_sp_chistics &chistics,
const st_sp_chistics &chistics, const AUTHID &definer,
const AUTHID &definer, sql_mode_t sql_mode) const
sql_mode_t sql_mode)
{ {
sql_mode_t old_sql_mode= thd->variables.sql_mode; sql_mode_t old_sql_mode= thd->variables.sql_mode;
/* Make some room to begin with */ /* Make some room to begin with */
@ -2203,10 +2202,8 @@ show_create_sp(THD *thd, String *buf,
if (thd->lex->create_info.or_replace()) if (thd->lex->create_info.or_replace())
buf->append(STRING_WITH_LEN("OR REPLACE ")); buf->append(STRING_WITH_LEN("OR REPLACE "));
append_definer(thd, buf, &definer.user, &definer.host); append_definer(thd, buf, &definer.user, &definer.host);
if (type == TYPE_ENUM_FUNCTION) buf->append(type_lex_cstring());
buf->append(STRING_WITH_LEN("FUNCTION ")); buf->append(STRING_WITH_LEN(" "));
else
buf->append(STRING_WITH_LEN("PROCEDURE "));
if (thd->lex->create_info.if_not_exists()) if (thd->lex->create_info.if_not_exists())
buf->append(STRING_WITH_LEN("IF NOT EXISTS ")); buf->append(STRING_WITH_LEN("IF NOT EXISTS "));
@ -2219,7 +2216,7 @@ show_create_sp(THD *thd, String *buf,
buf->append('('); buf->append('(');
buf->append(params); buf->append(params);
buf->append(')'); buf->append(')');
if (type == TYPE_ENUM_FUNCTION) if (type() == TYPE_ENUM_FUNCTION)
{ {
if (sql_mode & MODE_ORACLE) if (sql_mode & MODE_ORACLE)
buf->append(STRING_WITH_LEN(" RETURN ")); buf->append(STRING_WITH_LEN(" RETURN "));
@ -2259,15 +2256,6 @@ show_create_sp(THD *thd, String *buf,
} }
static LEX_CSTRING empty_body_lex_cstring(stored_procedure_type type)
{
static LEX_CSTRING empty_body_func= {C_STRING_WITH_LEN("RETURN NULL")};
static LEX_CSTRING empty_body_proc= {C_STRING_WITH_LEN("BEGIN END")};
return type == TYPE_ENUM_FUNCTION ? empty_body_func :
empty_body_proc;
}
/** /**
@brief The function loads sp_head struct for information schema purposes @brief The function loads sp_head struct for information schema purposes
(used for I_S ROUTINES & PARAMETERS tables). (used for I_S ROUTINES & PARAMETERS tables).
@ -2289,21 +2277,19 @@ static LEX_CSTRING empty_body_lex_cstring(stored_procedure_type type)
*/ */
sp_head * sp_head *
sp_load_for_information_schema(THD *thd, TABLE *proc_table, Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
stored_procedure_type type, const LEX_CSTRING &db,
const LEX_CSTRING &db, const LEX_CSTRING &name,
const LEX_CSTRING &name, const LEX_CSTRING &params,
const LEX_CSTRING &params, const LEX_CSTRING &returns,
const LEX_CSTRING &returns, sql_mode_t sql_mode,
sql_mode_t sql_mode, bool *free_sp_head) const
bool *free_sp_head)
{ {
String defstr; String defstr;
const AUTHID definer= {{STRING_WITH_LEN("")}, {STRING_WITH_LEN("")}}; const AUTHID definer= {{STRING_WITH_LEN("")}, {STRING_WITH_LEN("")}};
sp_head *sp; sp_head *sp;
sp_cache **spc= ((type == TYPE_ENUM_PROCEDURE) ? sp_cache **spc= get_cache(thd);
&thd->sp_proc_cache : &thd->sp_func_cache); sp_name sp_name_obj(&db, &name, true); // This can change "name"
sp_name sp_name_obj(&db, &name, true);
*free_sp_head= 0; *free_sp_head= 0;
if ((sp= sp_cache_lookup(spc, &sp_name_obj))) if ((sp= sp_cache_lookup(spc, &sp_name_obj)))
{ {
@ -2314,9 +2300,9 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table,
Stored_program_creation_ctx *creation_ctx= Stored_program_creation_ctx *creation_ctx=
Stored_routine_creation_ctx::load_from_db(thd, &sp_name_obj, proc_table); Stored_routine_creation_ctx::load_from_db(thd, &sp_name_obj, proc_table);
defstr.set_charset(creation_ctx->get_client_cs()); defstr.set_charset(creation_ctx->get_client_cs());
if (!show_create_sp(thd, &defstr, type, if (!show_create_sp(thd, &defstr,
sp_name_obj.m_db, sp_name_obj.m_name, sp_name_obj.m_db, sp_name_obj.m_name,
params, returns, empty_body_lex_cstring(type), params, returns, empty_body_lex_cstring(),
Sp_chistics(), definer, sql_mode)) Sp_chistics(), definer, sql_mode))
return 0; return 0;

331
sql/sp.h
View File

@ -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 &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
longlong created, longlong modified,
Stored_program_creation_ctx *creation_ctx) const;
int sp_drop_routine_internal(THD *thd,
const Database_qualified_name *name,
TABLE *table) const;
public:
static const Sp_handler *handler(enum enum_sql_command cmd);
static const Sp_handler *handler(stored_procedure_type type);
static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
const char *type_str() const { return type_lex_cstring().str; }
virtual const char *show_create_routine_col1_caption() const
{
DBUG_ASSERT(0);
return "";
}
virtual const char *show_create_routine_col3_caption() const
{
DBUG_ASSERT(0);
return "";
}
virtual stored_procedure_type type() const= 0;
virtual LEX_CSTRING type_lex_cstring() const= 0;
virtual LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("???")};
DBUG_ASSERT(0);
return m_empty_body;
}
virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0;
virtual sp_cache **get_cache(THD *) const { return NULL; }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
virtual HASH *get_priv_hash() const { return NULL; }
#endif
virtual ulong recursion_depth(THD *thd) const { return 0; }
/**
Return appropriate error about recursion limit reaching
@param thd Thread handle
@param sp SP routine
@remark For functions and triggers we return error about
prohibited recursion. For stored procedures we
return about reaching recursion limit.
*/
virtual void recursion_level_error(THD *thd, const sp_head *sp) const
{
my_error(ER_SP_NO_RECURSION, MYF(0));
}
virtual bool add_instr_freturn(THD *thd, sp_head *sp,
sp_pcontext *spcont,
Item *item, LEX *lex) const;
virtual bool add_instr_preturn(THD *thd, sp_head *sp,
sp_pcontext *spcont) const;
void add_used_routine(Query_tables_list *prelocking_ctx,
Query_arena *arena,
const Database_qualified_name *rt) const;
sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name,
bool cache_only) const;
int sp_cache_routine(THD *thd, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const;
bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
bool sp_show_create_routine(THD *thd,
const Database_qualified_name *name) const;
bool sp_create_routine(THD *thd, const sp_head *sp) const;
int sp_update_routine(THD *thd, const Database_qualified_name *name,
const st_sp_chistics *chistics) const;
int sp_drop_routine(THD *thd, const Database_qualified_name *name) const;
sp_head *sp_load_for_information_schema(THD *thd, TABLE *proc_table,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
sql_mode_t sql_mode,
bool *free_sp_head) const;
bool show_create_sp(THD *thd, String *buf,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
sql_mode_t sql_mode) const;
};
class Sp_handler_procedure: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PROCEDURE")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Procedure";
}
const char *show_create_routine_col3_caption() const
{
return "Create Procedure";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::PROCEDURE;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
ulong recursion_depth(THD *thd) const;
void recursion_level_error(THD *thd, const sp_head *sp) const;
bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const;
};
class Sp_handler_function: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("FUNCTION")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("RETURN NULL")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Function";
}
const char *show_create_routine_col3_caption() const
{
return "Create Function";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::FUNCTION;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont,
Item *item, LEX *lex) const;
};
class Sp_handler_trigger: public Sp_handler
{
public:
stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("TRIGGER")};
return m_type_str;
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
DBUG_ASSERT(0);
return MDL_key::TRIGGER;
}
};
extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
{
switch (cmd) {
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_STATUS_PROC:
return &sp_handler_procedure;
case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_ALTER_FUNCTION:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_SHOW_FUNC_CODE:
case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_STATUS_FUNC:
return &sp_handler_function;
default:
break;
}
return NULL;
}
inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
{ {
switch (type) { 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,16 +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,
stored_procedure_type type,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
sql_mode_t sql_mode,
bool *free_sp_head);
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,
@ -234,16 +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 LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
sql_mode_t sql_mode);
#endif /* _SP_H_ */ #endif /* _SP_H_ */

View File

@ -540,10 +540,10 @@ sp_head::operator delete(void *ptr, size_t size) throw()
} }
sp_head::sp_head(stored_procedure_type type) sp_head::sp_head(const Sp_handler *sph)
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP), :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)
@ -2532,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;
} }
@ -2541,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
@ -2551,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;
@ -2604,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
@ -2613,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;
@ -2634,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);
@ -2763,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".

View File

@ -40,11 +40,6 @@
@{ @{
*/ */
// Values for the type enum. This reflects the order of the enum declaration
// in the CREATE TABLE command.
//#define TYPE_ENUM_FUNCTION 1 #define TYPE_ENUM_PROCEDURE 2 #define
//TYPE_ENUM_TRIGGER 3 #define TYPE_ENUM_PROXY 4
Item::Type 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;
/** /**
@ -718,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)
{ {
@ -1864,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 *

View File

@ -754,6 +754,19 @@ static int traverse_role_graph_down(ACL_USER_BASE *, void *,
int (*) (ACL_USER_BASE *, void *), int (*) (ACL_USER_BASE *, 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;
} }

View File

@ -215,7 +215,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list, 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);

View File

@ -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);
} }
} }

View File

@ -5149,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"));
@ -5825,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);
@ -6127,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());

View File

@ -3156,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);

View File

@ -2937,13 +2937,13 @@ static int mysql_create_routine(THD *thd, LEX *lex)
{ {
if (check_routine_access(thd, ALTER_PROC_ACL, lex->sphead->m_db.str, 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_CREATE_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);
} }

View File

@ -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,

View File

@ -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);

View File

@ -5880,7 +5880,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
LEX_CSTRING db, name; LEX_CSTRING db, name;
char path[FN_REFLEN]; char path[FN_REFLEN];
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");
@ -5892,32 +5892,32 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db); proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name); proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &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.str); full_access= !strcmp(sp_user, definer.str);
if (!full_access && if (!full_access &&
check_some_routine_access(thd, db.str, name.str, check_some_routine_access(thd, db.str, name.str, sph))
routine_type == TYPE_ENUM_PROCEDURE))
DBUG_RETURN(0); DBUG_RETURN(0);
proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params); &params);
if (routine_type == TYPE_ENUM_FUNCTION) if (sph->type() == TYPE_ENUM_FUNCTION)
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns); &returns);
sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
sp= sp_load_for_information_schema(thd, proc_table, routine_type, db, name, params, returns,
params, returns, (ulong) proc_table->
(ulong) proc_table-> field[MYSQL_PROC_FIELD_SQL_MODE]->
field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(), val_int(),
&free_sp_head); &free_sp_head);
if (sp) if (sp)
{ {
Field *field; Field *field;
LEX_CSTRING 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);
@ -6000,26 +6000,27 @@ 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;
const Sp_handler *sph;
LEX_CSTRING db, name, definer, returns= empty_clex_str; LEX_CSTRING db, name, definer, returns= empty_clex_str;
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db); proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name); proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer); proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
sph= Sp_handler::handler((stored_procedure_type)
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
if (!sph)
sph= &sp_handler_procedure;
if (!full_access) if (!full_access)
full_access= !strcmp(sp_user, definer.str); full_access= !strcmp(sp_user, definer.str);
if (!full_access && if (!full_access &&
check_some_routine_access(thd, db.str, name.str, 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);
@ -6036,22 +6037,20 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
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_nopad(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns); &returns);
sp= sp_load_for_information_schema(thd, proc_table, sp= sph->sp_load_for_information_schema(thd, proc_table,
TYPE_ENUM_FUNCTION, db, name, db, name,
empty_clex_str /*params*/, empty_clex_str /*params*/,
returns, returns,
(ulong) proc_table-> (ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]-> field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(), val_int(),
&free_sp_head); &free_sp_head);
if (sp) if (sp)
{ {
char path[FN_REFLEN]; char path[FN_REFLEN];

View File

@ -2947,7 +2947,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());
@ -3045,7 +3045,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 {}
; ;
@ -3879,20 +3879,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;
} }
; ;
@ -16588,7 +16577,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());
@ -16662,7 +16651,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
@ -16697,7 +16686,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

View File

@ -2388,7 +2388,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());
@ -2491,7 +2491,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 {}
; ;
@ -3379,7 +3379,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
@ -3389,7 +3389,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
; ;
@ -3453,36 +3453,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;
} }
; ;
@ -16825,7 +16805,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());
@ -16901,7 +16881,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
@ -16939,7 +16919,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

View File

@ -2241,14 +2241,14 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
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(); 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 : null_clex_str, sp->m_explicit_name ? sp->m_db : null_clex_str,
sp->m_name, sp->m_params, returns, sp->m_name, sp->m_params, returns,
sp->m_body, sp->chistics(), thd->lex->definer[0], sp->m_body, sp->chistics(), thd->lex->definer[0],