Commit 0f1cadd9 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-13450 Cleanup SP code for packages

parent b3977ac2
......@@ -711,6 +711,23 @@ Sp_handler::db_find_routine(THD *thd,
}
int
Sp_handler::db_find_and_cache_routine(THD *thd,
const Database_qualified_name *name,
sp_head **sp) const
{
int rc= db_find_routine(thd, name, sp);
if (rc == SP_OK)
{
sp_cache_insert(get_cache(thd), *sp);
DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x",
(ulong) sp[0], sp[0]->m_recursion_level,
sp[0]->m_flags));
}
return rc;
}
/**
Silence DEPRECATED SYNTAX warnings when loading a stored procedure
into the cache.
......@@ -1335,6 +1352,26 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
}
static bool
append_suid(String *buf, enum_sp_suid_behaviour suid)
{
return suid == SP_IS_NOT_SUID &&
buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n"));
}
static bool
append_comment(String *buf, const LEX_CSTRING &comment)
{
if (!comment.length)
return false;
if (buf->append(STRING_WITH_LEN(" COMMENT ")))
return true;
append_unescaped(buf, comment.str, comment.length);
return buf->append('\n');
}
/**
Delete the record for the stored routine object from mysql.proc
and do binary logging.
......@@ -1711,36 +1748,21 @@ Sp_handler::sp_show_create_routine(THD *thd,
}
/**
Obtain object representing stored procedure/function by its name from
stored procedures cache and looking into mysql.proc if needed.
@param thd thread context
@param name name of procedure
@param cp hash to look routine in
@param cache_only if true perform cache-only lookup
(Don't look in mysql.proc).
@retval
NonNULL pointer to sp_head object for the procedure
@retval
NULL in case of error.
/*
In case of recursions, we create multiple copies of the same SP.
This methods checks the current recursion depth.
In case if the recursion limit exceeded, it throws an error
and returns NULL.
Otherwise, depending on the current recursion level, it:
- either returns the original SP,
- or makes and returns a new clone of SP
*/
sp_head *
Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
bool cache_only) const
Sp_handler::sp_clone_and_link_routine(THD *thd,
const Database_qualified_name *name,
sp_head *sp) const
{
sp_cache **cp= get_cache(thd);
sp_head *sp;
DBUG_ENTER("sp_find_routine");
DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d",
(int) name->m_db.length, name->m_db.str,
(int) name->m_name.length, name->m_name.str,
type_str(), cache_only));
if ((sp= sp_cache_lookup(cp, name)))
{
DBUG_ENTER("sp_link_routine");
ulong level;
sp_head *new_sp;
LEX_CSTRING returns= empty_clex_str;
......@@ -1802,17 +1824,41 @@ Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
DBUG_RETURN(new_sp);
}
DBUG_RETURN(0);
}
}
/**
Obtain object representing stored procedure/function by its name from
stored procedures cache and looking into mysql.proc if needed.
@param thd thread context
@param name name of procedure
@param cp hash to look routine in
@param cache_only if true perform cache-only lookup
(Don't look in mysql.proc).
@retval
NonNULL pointer to sp_head object for the procedure
@retval
NULL in case of error.
*/
sp_head *
Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
bool cache_only) const
{
DBUG_ENTER("sp_find_routine");
DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d",
(int) name->m_db.length, name->m_db.str,
(int) name->m_name.length, name->m_name.str,
type_str(), cache_only));
sp_cache **cp= get_cache(thd);
sp_head *sp;
if ((sp= sp_cache_lookup(cp, name)))
DBUG_RETURN(sp_clone_and_link_routine(thd, name, sp));
if (!cache_only)
{
if (db_find_routine(thd, name, &sp) == SP_OK)
{
sp_cache_insert(cp, sp);
DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x",
(ulong)sp, sp->m_recursion_level,
sp->m_flags));
}
}
db_find_and_cache_routine(thd, name, &sp);
DBUG_RETURN(sp);
}
......@@ -2137,10 +2183,9 @@ int Sp_handler::sp_cache_routine(THD *thd,
DBUG_RETURN(SP_OK);
}
switch ((ret= db_find_routine(thd, name, sp)))
switch ((ret= db_find_and_cache_routine(thd, name, sp)))
{
case SP_OK:
sp_cache_insert(spc, *sp);
break;
case SP_KEY_NOT_FOUND:
ret= SP_OK;
......@@ -2243,14 +2288,8 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
}
if (chistics.detistic)
buf->append(STRING_WITH_LEN(" DETERMINISTIC\n"));
if (chistics.suid == SP_IS_NOT_SUID)
buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n"));
if (chistics.comment.length)
{
buf->append(STRING_WITH_LEN(" COMMENT "));
append_unescaped(buf, chistics.comment.str, chistics.comment.length);
buf->append('\n');
}
append_suid(buf, chistics.suid);
append_comment(buf, chistics.comment);
buf->append(body);
thd->variables.sql_mode= old_sql_mode;
return false;
......
......@@ -60,6 +60,9 @@ class Sp_handler
TABLE *table) const;
int db_find_routine(THD *thd, const Database_qualified_name *name,
sp_head **sphp) const;
int db_find_and_cache_routine(THD *thd,
const Database_qualified_name *name,
sp_head **sp) const;
int db_load_routine(THD *thd, const Database_qualified_name *name,
sp_head **sphp,
sql_mode_t sql_mode,
......@@ -73,6 +76,10 @@ class Sp_handler
int sp_drop_routine_internal(THD *thd,
const Database_qualified_name *name,
TABLE *table) const;
sp_head *sp_clone_and_link_routine(THD *thd,
const Database_qualified_name *name,
sp_head *sp) const;
public:
static const Sp_handler *handler(enum enum_sql_command cmd);
static const Sp_handler *handler(stored_procedure_type type);
......
......@@ -5798,7 +5798,7 @@ bool LEX::sp_block_finalize(THD *thd, const Lex_spblock_st spblock,
}
sp_name *LEX::make_sp_name(THD *thd, LEX_CSTRING *name)
sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name)
{
sp_name *res;
LEX_CSTRING db;
......@@ -5810,16 +5810,20 @@ sp_name *LEX::make_sp_name(THD *thd, LEX_CSTRING *name)
}
sp_name *LEX::make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2)
sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2)
{
sp_name *res;
if (!name1->str || check_db_name((LEX_STRING*) name1))
LEX_CSTRING norm_name1;
if (!name1->str ||
!thd->make_lex_string(&norm_name1, name1->str, name1->length) ||
check_db_name((LEX_STRING *) &norm_name1))
{
my_error(ER_WRONG_DB_NAME, MYF(0), name1->str);
return NULL;
}
if (check_routine_name(name2) ||
(!(res= new (thd->mem_root) sp_name(name1, name2, true))))
(!(res= new (thd->mem_root) sp_name(&norm_name1, name2, true))))
return NULL;
return res;
}
......@@ -6570,6 +6574,18 @@ Item *LEX::create_item_limit(THD *thd,
}
bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
{
Item_func_set_user_var *item;
set_var_user *var;
if (!(item= new (thd->mem_root) Item_func_set_user_var(thd, name, val)) ||
!(var= new (thd->mem_root) set_var_user(item)))
return true;
var_list.push_back(var, thd->mem_root);
return false;
}
/*
Perform assignment for a trigger, a system variable, or an SP variable.
"variable" be previously set by init_internal_variable(variable, name).
......@@ -7101,3 +7117,42 @@ bool LEX::add_create_view(THD *thd, DDL_options_st ddl,
return true;
return create_or_alter_view_finalize(thd, table_ident);
}
bool LEX::call_statement_start(THD *thd, sp_name *name)
{
sql_command= SQLCOM_CALL;
spname= name;
value_list.empty();
sp_handler_procedure.add_used_routine(this, thd, name);
return false;
}
bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name)
{
sp_name *spname= make_sp_name(thd, name);
return !spname || call_statement_start(thd, spname);
}
bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2)
{
sp_name *spname= make_sp_name(thd, name1, name2);
return !spname || call_statement_start(thd, spname);
}
bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg)
{
if (columns.elements)
{
thd->parse_error();
return true;
}
sql_command= sql_command_arg,
type= type_arg;
return false;
}
......@@ -3153,9 +3153,11 @@ struct LEX: public Query_tables_list
bool set_trigger_new_row(LEX_CSTRING *name, Item *val);
bool set_system_variable(struct sys_var_with_base *tmp,
enum enum_var_type var_type, Item *val);
bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val);
void set_stmt_init();
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name);
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2);
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name);
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2);
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph);
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
const Sp_handler *sph)
......@@ -3173,6 +3175,10 @@ struct LEX: public Query_tables_list
return NULL;
return make_sp_head_no_recursive(thd, name, sph);
}
bool call_statement_start(THD *thd, sp_name *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2);
bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name);
bool init_internal_variable(struct sys_var_with_base *variable,
......@@ -3651,6 +3657,9 @@ struct LEX: public Query_tables_list
bool add_create_view(THD *thd, DDL_options_st ddl,
uint16 algorithm, enum_view_suid suid,
Table_ident *table_ident);
bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg);
};
......
......@@ -3040,12 +3040,8 @@ sp_suid:
call:
CALL_SYM sp_name
{
LEX *lex = Lex;
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
sp_handler_procedure.add_used_routine(lex, thd, $2);
if (Lex->call_statement_start(thd, $2))
MYSQL_YYABORT;
}
opt_sp_cparam_list {}
;
......@@ -15172,14 +15168,8 @@ option_value_no_option_type:
}
| '@' ident_or_text equal expr
{
Item_func_set_user_var *item;
item= new (thd->mem_root) Item_func_set_user_var(thd, &$2, $4);
if (item == NULL)
MYSQL_YYABORT;
set_var_user *var= new (thd->mem_root) set_var_user(item);
if (var == NULL)
if (Lex->set_user_variable(thd, &$2, $4))
MYSQL_YYABORT;
Lex->var_list.push_back(var, thd->mem_root);
}
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
......@@ -15584,26 +15574,14 @@ revoke_command:
}
| grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_FUNCTION))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
}
| grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE;
}
| ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
{
Lex->sql_command = SQLCOM_REVOKE_ALL;
......@@ -15646,27 +15624,15 @@ grant_command:
| grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_FUNCTION))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
}
| grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
}
| PROXY_SYM ON user TO_SYM grant_list opt_grant_option
{
LEX *lex= Lex;
......
......@@ -2486,12 +2486,8 @@ sp_suid:
call:
CALL_SYM sp_name
{
LEX *lex = Lex;
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
sp_handler_procedure.add_used_routine(lex, thd, $2);
if (Lex->call_statement_start(thd, $2))
MYSQL_YYABORT;
}
opt_sp_cparam_list {}
;
......@@ -3374,22 +3370,14 @@ sp_statement:
| ident_directly_assignable
{
// Direct procedure call (without the CALL keyword)
LEX *lex = Lex;
if (!(lex->spname= lex->make_sp_name(thd, &$1)))
if (Lex->call_statement_start(thd, &$1))
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
| ident_directly_assignable '.' ident
{
LEX *lex = Lex;
if (!(lex->spname= lex->make_sp_name(thd, &$1, &$3)))
if (Lex->call_statement_start(thd, &$1, &$3))
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
;
......@@ -15385,14 +15373,8 @@ option_value_no_option_type:
}
| '@' ident_or_text equal expr
{
Item_func_set_user_var *item;
item= new (thd->mem_root) Item_func_set_user_var(thd, &$2, $4);
if (item == NULL)
MYSQL_YYABORT;
set_var_user *var= new (thd->mem_root) set_var_user(item);
if (var == NULL)
if (Lex->set_user_variable(thd, &$2, $4))
MYSQL_YYABORT;
Lex->var_list.push_back(var, thd->mem_root);
}
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
......@@ -15821,26 +15803,14 @@ revoke_command:
}
| grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_FUNCTION))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
}
| grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE;
}
| ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
{
Lex->sql_command = SQLCOM_REVOKE_ALL;
......@@ -15883,27 +15853,15 @@ grant_command:
| grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_FUNCTION))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
}
| grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
thd->parse_error();
if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
}
| PROXY_SYM ON user TO_SYM grant_list opt_grant_option
{
LEX *lex= Lex;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment