diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-08-15 14:13:42 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-08-15 14:13:42 +0400 |
commit | 4d50594dfc758774f116d3919a2a039f95182f8e (patch) | |
tree | 3aab020bd53f09edb67d9400b97d1d32083e8355 | |
parent | 966cc80299d7ebc6b63427e3a94c5218cb8e240d (diff) | |
download | mariadb-git-4d50594dfc758774f116d3919a2a039f95182f8e.tar.gz |
MDEV-13529 Add class Sql_cmd_call
-rw-r--r-- | mysql-test/r/lowercase_fs_off.result | 2 | ||||
-rw-r--r-- | sql/item_func.cc | 25 | ||||
-rw-r--r-- | sql/item_func.h | 2 | ||||
-rw-r--r-- | sql/sp_head.cc | 8 | ||||
-rw-r--r-- | sql/sp_head.h | 2 | ||||
-rw-r--r-- | sql/sql_cmd.h | 29 | ||||
-rw-r--r-- | sql/sql_lex.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 118 |
8 files changed, 120 insertions, 68 deletions
diff --git a/mysql-test/r/lowercase_fs_off.result b/mysql-test/r/lowercase_fs_off.result index 12da5127629..91bd2924096 100644 --- a/mysql-test/r/lowercase_fs_off.result +++ b/mysql-test/r/lowercase_fs_off.result @@ -61,7 +61,7 @@ connect con2,localhost,USER_1,,db1; call p1(); ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' call P1(); -ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.P1' +ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' select f1(1); ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.f1' connection default; diff --git a/sql/item_func.cc b/sql/item_func.cc index ebd5d9860d6..8a2db6bc0d5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6256,7 +6256,7 @@ void my_missing_function_error(const LEX_CSTRING &token, const char *func_name) */ bool -Item_func_sp::init_result_field(THD *thd) +Item_func_sp::init_result_field(THD *thd, sp_head *sp) { TABLE_SHARE *share; DBUG_ENTER("Item_func_sp::init_result_field"); @@ -6264,7 +6264,7 @@ Item_func_sp::init_result_field(THD *thd) DBUG_ASSERT(m_sp == NULL); DBUG_ASSERT(sp_result_field == NULL); - if (!(m_sp= sp_handler_function.sp_find_routine(thd, m_name, true))) + if (!(m_sp= sp)) { my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr()); context->process_error(thd); @@ -6512,12 +6512,7 @@ Item_func_sp::sp_check_access(THD *thd) { DBUG_ENTER("Item_func_sp::sp_check_access"); DBUG_ASSERT(m_sp); - if (check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, - &sp_handler_function, false)) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); + DBUG_RETURN(m_sp->check_execute_access(thd)); } @@ -6527,6 +6522,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) bool res; DBUG_ENTER("Item_func_sp::fix_fields"); DBUG_ASSERT(fixed == 0); + sp_head *sp= sp_handler_function.sp_find_routine(thd, m_name, true); /* Checking privileges to execute the function while creating view and @@ -6539,9 +6535,14 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) if (context->security_ctx) thd->security_ctx= context->security_ctx; - res= check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str, - m_name->m_name.str, - &sp_handler_function, false); + /* + If the routine is not found, let's still check EXECUTE_ACL to decide + whether to return "Access denied" or "Routine does not exist". + */ + res= sp ? sp->check_execute_access(thd) : + check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str, + m_name->m_name.str, + &sp_handler_function, false); thd->security_ctx= save_security_ctx; if (res) @@ -6556,7 +6557,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) to make m_sp and result_field members available to fix_length_and_dec(), which is called from Item_func::fix_fields(). */ - res= init_result_field(thd); + res= init_result_field(thd, sp); if (res) DBUG_RETURN(res); diff --git a/sql/item_func.h b/sql/item_func.h index 91129d27fe5..9a6254438f0 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2679,7 +2679,7 @@ private: bool execute(); bool execute_impl(THD *thd); - bool init_result_field(THD *thd); + bool init_result_field(THD *thd, sp_head *sp); protected: bool is_expensive_processor(void *arg) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1f71139b9af..f9d3aa56458 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1424,6 +1424,14 @@ set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx) #endif // ! NO_EMBEDDED_ACCESS_CHECKS +bool sp_head::check_execute_access(THD *thd) const +{ + return check_routine_access(thd, EXECUTE_ACL, + m_db.str, m_name.str, + m_handler, false); +} + + /** Create rcontext using the routine security. This is important for sql_mode=ORACLE to make sure that the invoker has diff --git a/sql/sp_head.h b/sql/sp_head.h index f9a021d535e..e3cedb6e30a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -791,6 +791,8 @@ public: sp_pcontext *get_parse_context() { return m_pcont; } + bool check_execute_access(THD *thd) const; + private: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 4ae9353d6ff..d95b1c828b9 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -167,4 +167,33 @@ protected: } }; + +/** + Sql_cmd_call represents the CALL statement. +*/ +class Sql_cmd_call : public Sql_cmd +{ +public: + class sp_name *m_name; + Sql_cmd_call(class sp_name *name) + :m_name(name) + {} + + virtual ~Sql_cmd_call() + {} + + /** + Execute a CALL statement at runtime. + @param thd the current thread. + @return false on success. + */ + bool execute(THD *thd); + + virtual enum_sql_command sql_command_code() const + { + return SQLCOM_CALL; + } +}; + + #endif // SQL_CMD_INCLUDED diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ea01bb04d9e..ef1a41a34a7 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7156,6 +7156,8 @@ bool LEX::call_statement_start(THD *thd, sp_name *name) sql_command= SQLCOM_CALL; spname= name; value_list.empty(); + if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_call(name))) + return true; sp_handler_procedure.add_used_routine(this, thd, name); return false; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c64ca8961ae..84bc7a4e4ed 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3074,6 +3074,69 @@ static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname) return check_access(thd, want_access, dbname->str, NULL, NULL, 1, 0); } + +bool Sql_cmd_call::execute(THD *thd) +{ + TABLE_LIST *all_tables= thd->lex->query_tables; + sp_head *sp; + /* + This will cache all SP and SF and open and lock all tables + required for execution. + */ + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, + UINT_MAX, FALSE) || + open_and_lock_tables(thd, all_tables, TRUE, 0)) + return true; + + /* + By this moment all needed SPs should be in cache so no need to look + into DB. + */ + if (!(sp= sp_handler_procedure.sp_find_routine(thd, m_name, true))) + { + /* + If the routine is not found, let's still check EXECUTE_ACL to decide + whether to return "Access denied" or "Routine does not exist". + */ + if (check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str, + m_name->m_name.str, + &sp_handler_procedure, + false)) + return true; + /* + sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. + Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in + cache. + */ + if (!sp_cache_lookup(&thd->sp_proc_cache, m_name)) + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", + ErrConvDQName(m_name).ptr()); + return true; + } + else + { + if (sp->check_execute_access(thd)) + return true; + /* + Check that the stored procedure doesn't contain Dynamic SQL + and doesn't return result sets: such stored procedures can't + be called from a function or trigger. + */ + if (thd->in_sub_stmt) + { + const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? + "trigger" : "function"); + if (sp->is_not_allowed_in_function(where)) + return true; + } + + if (do_execute_sp(thd, sp)) + return true; + } + return false; +} + + /** Execute command saved in thd and lex->sql_command. @@ -5748,60 +5811,6 @@ end_with_restore_list: my_ok(thd); break; /* break super switch */ } /* end case group bracket */ - case SQLCOM_CALL: - { - sp_head *sp; - /* - This will cache all SP and SF and open and lock all tables - required for execution. - */ - if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, - UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables, TRUE, 0)) - goto error; - - if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str, - lex->spname->m_name.str, &sp_handler_procedure, - false)) - goto error; - - /* - By this moment all needed SPs should be in cache so no need to look - into DB. - */ - if (!(sp= sp_handler_procedure.sp_find_routine(thd, lex->spname, true))) - { - /* - sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. - Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in - cache. - */ - if (!sp_cache_lookup(&thd->sp_proc_cache, lex->spname)) - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", - ErrConvDQName(lex->spname).ptr()); - goto error; - } - else - { - /* - Check that the stored procedure doesn't contain Dynamic SQL - and doesn't return result sets: such stored procedures can't - be called from a function or trigger. - */ - if (thd->in_sub_stmt) - { - const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? - "trigger" : "function"); - if (sp->is_not_allowed_in_function(where)) - goto error; - } - - if (do_execute_sp(thd, sp)) - goto error; - } - break; - } - case SQLCOM_COMPOUND: DBUG_ASSERT(all_tables == 0); DBUG_ASSERT(thd->in_sub_stmt == 0); @@ -6196,6 +6205,7 @@ end_with_restore_list: case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: case SQLCOM_GET_DIAGNOSTICS: + case SQLCOM_CALL: DBUG_ASSERT(lex->m_sql_cmd != NULL); res= lex->m_sql_cmd->execute(thd); break; |