revision-id: f953315f68e21c9a994c9c30d02589631e4778a7 (mariadb-10.4.1-75-gf953315) parent(s): 301bd62b2536f85a8ce418dcd5e705796d8c5763 committer: Alexey Botchkov timestamp: 2019-01-14 20:17:55 +0400 message: MDEV-5313 Improving audit api. The 'run query from plugin' proposal interface. Consists of a single function 'run_plugin_proc', that gets the 'stored function with no args returning TEXT' in plain string format, runs it and returns the TEXT result. --- plugin/server_audit/server_audit.c | 18 ++++++ sql/sp.cc | 120 +++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index a9b4ff2..968d8b5 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -2325,6 +2325,23 @@ typedef struct loc_system_variables static int init_done= 0; +extern int run_plugin_proc(const char *proc, size_t proc_len, + char *result, size_t result_buf_len, size_t *result_len); + +static const char *sel0= + "CREATE DEFINER=`root`@`localhost` FUNCTION `lipi`() RETURNS TEXT\n" + "begin declare v TEXT; select concat('Value: ', s1) from lipi_t into v; return v; end"; + +int runselect() +{ + char buf[1024]; + size_t res_len; + int res; + + res= run_plugin_proc(sel0, strlen(sel0), buf, sizeof(buf), &res_len); + return res; +} + static int server_audit_init(void *p __attribute__((unused))) { if (!serv_ver) @@ -2433,6 +2450,7 @@ static int server_audit_init(void *p __attribute__((unused))) if (logging) start_logging(); + runselect(); init_done= 1; return 0; } diff --git a/sql/sp.cc b/sql/sp.cc index 6b38a0d..647f201 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -273,6 +273,7 @@ class Stored_routine_creation_ctx : public Stored_program_creation_ctx, : Stored_program_creation_ctx(thd) { } +public: Stored_routine_creation_ctx(CHARSET_INFO *client_cs, CHARSET_INFO *connection_cl, CHARSET_INFO *db_cl) @@ -3056,3 +3057,122 @@ LEX_CSTRING Sp_handler_function::empty_body_lex_cstring(sql_mode_t mode) const static LEX_CSTRING m_empty_body_ora= {STRING_WITH_LEN("AS BEGIN RETURN NULL; END")}; return mode & MODE_ORACLE ? m_empty_body_ora : m_empty_body_std; } + + +static Stored_routine_creation_ctx rs_ctx(&my_charset_bin, + &my_charset_bin, + &my_charset_bin); + +#include "sp_rcontext.h" //sp_rcontext declaration + +extern "C" int run_plugin_proc(const char *proc, size_t proc_len, + char *result, size_t result_buf_len, size_t *result_len) +{ + THD *thd= current_thd; + LEX *old_lex= thd->lex, newlex; + TABLE *dummy_table; + MEM_ROOT sp_mem_root; + String defstr(proc, proc_len, system_charset_info); + sql_mode_t sql_mode; + Sp_chistics chistics; + Query_arena *sp_query_arena; + Field *sp_result_field; + uchar result_buf[10]; + uchar null_buf[1]; + //Stored_program_creation_ctx *creation_ctx; + Sub_statement_state statement_state; + sp_rcontext *func_ctx= NULL; + String buf; + int err_status= 1; + + thd->lex= &newlex; + newlex.current_select= NULL; + + sql_mode= thd->variables.sql_mode; + + sp_head *pi= sp_compile(thd, &defstr, sql_mode, NULL, &rs_ctx); + { + /* Set current user as a definer. */ + CHARSET_INFO *cs= system_charset_info; + const char *user= thd->security_ctx->user; + const char *host= thd->security_ctx->host; + size_t res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen; + if (buf.alloc((uint) res_length)) + goto error; + res_length= cs->cset->snprintf(cs, (char*)buf.ptr(), (uint) res_length, + "%s@%s", user, host); + buf.length(res_length); + pi->set_definer(buf.ptr(), buf.length()); + } + chistics.suid= SP_IS_SUID; + chistics.daccess= SP_CONTAINS_SQL; + chistics.agg_type= NOT_AGGREGATE; + pi->set_info(0, 0, chistics, sql_mode); + pi->set_creation_ctx(&rs_ctx); + pi->optimize(); + + newlex.set_trg_event_type_for_tables(); + thd->lex->sphead= NULL; + lex_end(thd->lex); + thd->lex= old_lex; + + /* Item_sp::Item_sp > */ + dummy_table= (TABLE*) thd->calloc(sizeof(TABLE) + sizeof(TABLE_SHARE) + + sizeof(Query_arena)); + dummy_table->s= (TABLE_SHARE*) (dummy_table + 1); + sp_query_arena= (Query_arena *) (dummy_table->s + 1); + memset(&sp_mem_root, 0, sizeof(sp_mem_root)); + /* < Item_sp::Item_sp */ + /* Item_sp::init_result_field > */ + /* + A Field needs to be attached to a Table. + Below we "create" a dummy table by initializing + the needed pointers. + */ + dummy_table->alias.set("", 0, table_alias_charset); + dummy_table->in_use= thd; + dummy_table->copy_blobs= TRUE; + dummy_table->s->table_cache_key= empty_clex_str; + dummy_table->s->table_name= empty_clex_str; + dummy_table->maybe_null= 1; + + if (!(sp_result_field= new (thd->mem_root) + Field_blob(result_buf, null_buf, 1, + Field::NONE, &empty_clex_str, + dummy_table->s, 2, &my_charset_latin1))) + goto error; + sp_result_field->init(dummy_table); + sp_result_field->null_bit= 1; //???? + + /* < Item_sp::init_result_field */ + + /* Item_sp::execute >*/ + thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION); + init_sql_alloc(&sp_mem_root, "ap_query", MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); + *sp_query_arena= Query_arena(&sp_mem_root, + Query_arena::STMT_INITIALIZED_FOR_SP); + + err_status= pi->execute_function(thd, NULL, 0, sp_result_field, + &func_ctx, sp_query_arena); + + delete func_ctx; + sp_query_arena->free_items(); + free_root(&sp_mem_root, MYF(0)); + + thd->restore_sub_statement_state(&statement_state); + sp_result_field->val_str(&buf); + *result_len= buf.length(); + if (buf.length() < result_buf_len) + result_buf_len= buf.length(); + + memcpy(result, buf.ptr(), result_buf_len); + + thd->lex->sphead= NULL; + lex_end(thd->lex); + thd->lex= old_lex; + + /* < Item_sp::execute */ +error: + return err_status; +} +