diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-08-04 16:33:58 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-08-04 16:33:58 +0400 |
commit | 0f1cadd9a5e6e8aa2103100502b0a5b4227e8d7b (patch) | |
tree | e595d36fd2f5d0f1d69114a2dada71e64f1bfb55 /sql | |
parent | b3977ac23f90c11be7f0f6e019239fd9580130cb (diff) | |
download | mariadb-git-0f1cadd9a5e6e8aa2103100502b0a5b4227e8d7b.tar.gz |
MDEV-13450 Cleanup SP code for packages
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp.cc | 207 | ||||
-rw-r--r-- | sql/sp.h | 7 | ||||
-rw-r--r-- | sql/sql_lex.cc | 63 | ||||
-rw-r--r-- | sql/sql_lex.h | 13 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 48 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 60 |
6 files changed, 216 insertions, 182 deletions
diff --git a/sql/sp.cc b/sql/sp.cc index 87061315987..015e2f77b21 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -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 @@ done: } +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,6 +1748,85 @@ Sp_handler::sp_show_create_routine(THD *thd, } +/* + 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_clone_and_link_routine(THD *thd, + const Database_qualified_name *name, + sp_head *sp) const +{ + DBUG_ENTER("sp_link_routine"); + ulong level; + sp_head *new_sp; + LEX_CSTRING returns= empty_clex_str; + + /* + String buffer for RETURNS data type must have system charset; + 64 -- size of "returns" column of mysql.proc. + */ + String retstr(64); + retstr.set_charset(sp->get_creation_ctx()->get_client_cs()); + + DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); + if (sp->m_first_free_instance) + { + DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x", + (ulong)sp->m_first_free_instance, + sp->m_first_free_instance->m_recursion_level, + sp->m_first_free_instance->m_flags)); + DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); + if (sp->m_first_free_instance->m_recursion_level > recursion_depth(thd)) + { + recursion_level_error(thd, sp); + DBUG_RETURN(0); + } + DBUG_RETURN(sp->m_first_free_instance); + } + /* + Actually depth could be +1 than the actual value in case a SP calls + SHOW CREATE PROCEDURE. Hence, the linked list could hold up to one more + instance. + */ + + level= sp->m_last_cached_sp->m_recursion_level + 1; + if (level > recursion_depth(thd)) + { + recursion_level_error(thd, sp); + DBUG_RETURN(0); + } + + if (type() == TYPE_ENUM_FUNCTION) + { + sp_returns_type(thd, retstr, sp); + returns= retstr.lex_cstring(); + } + if (db_load_routine(thd, name, &new_sp, + sp->m_sql_mode, sp->m_params, returns, + sp->m_body, sp->chistics(), + sp->m_definer, + sp->m_created, sp->m_modified, + sp->get_creation_ctx()) == SP_OK) + { + sp->m_last_cached_sp->m_next_cached_sp= new_sp; + new_sp->m_recursion_level= level; + new_sp->m_first_instance= sp; + sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; + DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", + (ulong)new_sp, new_sp->m_recursion_level, + new_sp->m_flags)); + 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. @@ -1731,88 +1847,18 @@ sp_head * Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name, bool cache_only) 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)); + sp_cache **cp= get_cache(thd); + sp_head *sp; if ((sp= sp_cache_lookup(cp, name))) - { - ulong level; - sp_head *new_sp; - LEX_CSTRING returns= empty_clex_str; - - /* - String buffer for RETURNS data type must have system charset; - 64 -- size of "returns" column of mysql.proc. - */ - String retstr(64); - retstr.set_charset(sp->get_creation_ctx()->get_client_cs()); - - DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); - if (sp->m_first_free_instance) - { - DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x", - (ulong)sp->m_first_free_instance, - sp->m_first_free_instance->m_recursion_level, - sp->m_first_free_instance->m_flags)); - DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); - if (sp->m_first_free_instance->m_recursion_level > recursion_depth(thd)) - { - recursion_level_error(thd, sp); - DBUG_RETURN(0); - } - DBUG_RETURN(sp->m_first_free_instance); - } - /* - Actually depth could be +1 than the actual value in case a SP calls - SHOW CREATE PROCEDURE. Hence, the linked list could hold up to one more - instance. - */ - - level= sp->m_last_cached_sp->m_recursion_level + 1; - if (level > recursion_depth(thd)) - { - recursion_level_error(thd, sp); - DBUG_RETURN(0); - } - - if (type() == TYPE_ENUM_FUNCTION) - { - sp_returns_type(thd, retstr, sp); - returns= retstr.lex_cstring(); - } - if (db_load_routine(thd, name, &new_sp, - sp->m_sql_mode, sp->m_params, returns, - sp->m_body, sp->chistics(), - sp->m_definer, - sp->m_created, sp->m_modified, - sp->get_creation_ctx()) == SP_OK) - { - sp->m_last_cached_sp->m_next_cached_sp= new_sp; - new_sp->m_recursion_level= level; - new_sp->m_first_instance= sp; - sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; - DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", - (ulong)new_sp, new_sp->m_recursion_level, - new_sp->m_flags)); - DBUG_RETURN(new_sp); - } - DBUG_RETURN(0); - } + 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); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ebaa0ee6eb5..5756cf6c485 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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; +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b72f52c5e4d..725a8e27fcb 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3153,9 +3153,11 @@ public: 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 @@ public: 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 @@ public: 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); }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 40850ccc43f..e7ea40ca334 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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,25 +15574,13 @@ 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 { @@ -15646,26 +15624,14 @@ 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 { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 7c4d8cb5c81..9a5ebe45468 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -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,25 +15803,13 @@ 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 { @@ -15883,26 +15853,14 @@ 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 { |