diff options
Diffstat (limited to 'sql')
175 files changed, 5613 insertions, 1932 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index da046d0ec3a..d0a3e8a437a 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -433,16 +433,9 @@ ADD_CUSTOM_TARGET(distclean VERBATIM ) -IF(INSTALL_LAYOUT STREQUAL "STANDALONE") - -# Copy db.opt into data/test/ -SET(DBOPT_FILE ${CMAKE_SOURCE_DIR}/support-files/db.opt ) -INSTALL(FILES ${DBOPT_FILE} DESTINATION data/test COMPONENT DataFiles) - -# Install initial database on windows -IF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING) - - IF(MSVC_IDE OR CMAKE_GENERATOR MATCHES "Xcode") +# Install initial database (default on windows, optional target elsewhere) +IF(TARGET mysqld AND NOT CMAKE_CROSSCOMPILING) + IF(GENERATOR_IS_MULTI_CONFIG) SET (CONFIG_PARAM -DCONFIG=${CMAKE_CFG_INTDIR}) ENDIF() MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data) @@ -461,15 +454,16 @@ IF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DEPENDS mysqld ) + IF(WIN32) + SET(ALL_ON_WINDOWS ALL) + ELSE() + SET(ALL_ON_WINDOWS) + ENDIF() ADD_CUSTOM_TARGET(initial_database - ALL + ${ALL_ON_WINDOWS} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep ) -ELSE() - # Not windows or cross compiling, just install an empty directory - INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql COMPONENT DataFiles) -ENDIF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING) -ENDIF(INSTALL_LAYOUT STREQUAL "STANDALONE") +ENDIF() IF(WIN32) SET(my_bootstrap_sql ${CMAKE_CURRENT_BINARY_DIR}/my_bootstrap.sql) diff --git a/sql/backup.cc b/sql/backup.cc index 1a0341ad9a4..40791e27416 100644 --- a/sql/backup.cc +++ b/sql/backup.cc @@ -161,7 +161,8 @@ static bool backup_start(THD *thd) DBUG_RETURN(1); } - mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_START, MDL_EXPLICIT); + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_START, + MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) DBUG_RETURN(1); diff --git a/sql/bounded_queue.h b/sql/bounded_queue.h index cd710d835aa..07ab6dbaab9 100644 --- a/sql/bounded_queue.h +++ b/sql/bounded_queue.h @@ -59,7 +59,8 @@ public: */ typedef uint (*keymaker_function)(Sort_param *param, Key_type *to, - Element_type *from); + Element_type *from, + bool packing_keys); /** Function for comparing two keys. @@ -181,11 +182,12 @@ void Bounded_queue<Element_type, Key_type>::push(Element_type *element) { // Replace top element with new key, and re-order the queue. Key_type **pq_top= reinterpret_cast<Key_type **>(queue_top(&m_queue)); - (void)(*m_keymaker)(m_sort_param, *pq_top, element); + (void)(*m_keymaker)(m_sort_param, *pq_top, element, false); queue_replace_top(&m_queue); } else { // Insert new key into the queue. - (*m_keymaker)(m_sort_param, m_sort_keys[m_queue.elements], element); + (*m_keymaker)(m_sort_param, m_sort_keys[m_queue.elements], + element, false); queue_insert(&m_queue, reinterpret_cast<uchar*>(&m_sort_keys[m_queue.elements])); } diff --git a/sql/create_options.cc b/sql/create_options.cc index 817c4ba46e0..04469120db1 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -407,7 +407,7 @@ static bool resolve_sysvars(handlerton *hton, ha_create_table_option *rules) return 1; } DBUG_ASSERT(str.length()); - opt->values= my_strndup(str.ptr(), str.length()-1, MYF(MY_WME)); + opt->values= my_strndup(PSI_INSTRUMENT_ME, str.ptr(), str.length()-1, MYF(MY_WME)); if (!opt->values) return 1; break; diff --git a/sql/datadict.cc b/sql/datadict.cc index da8376d8b1a..5cfda166b2b 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -25,7 +25,7 @@ static int read_string(File file, uchar**to, size_t length) DBUG_ENTER("read_string"); /* This can't use MY_THREAD_SPECIFIC as it's used on server start */ - if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) || + if (!(*to= (uchar*) my_malloc(PSI_INSTRUMENT_ME, length+1,MYF(MY_WME))) || mysql_file_read(file, *to, length, MYF(MY_NABP))) { my_free(*to); diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index af541b1bb32..fdca2c47dbc 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -122,6 +122,25 @@ static void init_debug_sync_psi_keys(void) /** + Set the THD::proc_info without instrumentation. + This method is private to DEBUG_SYNC, + and on purpose avoid any use of: + - the SHOW PROFILE instrumentation + - the PERFORMANCE_SCHEMA instrumentation + so that using DEBUG_SYNC() in the server code + does not cause the instrumentations to record + spurious data. +*/ +static const char* +debug_sync_thd_proc_info(THD *thd, const char* info) +{ + const char* old_proc_info= thd->proc_info; + thd->proc_info= info; + return old_proc_info; +} + + +/** Initialize the debug sync facility at server start. @return status @@ -236,7 +255,8 @@ void debug_sync_init_thread(THD *thd) if (opt_debug_sync_timeout) { thd->debug_sync_control= (st_debug_sync_control*) - my_malloc(sizeof(st_debug_sync_control), + my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(st_debug_sync_control), MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC)); if (!thd->debug_sync_control) { @@ -657,7 +677,7 @@ static st_debug_sync_action *debug_sync_get_action(THD *thd, if (ds_control->ds_active > ds_control->ds_allocated) { uint new_alloc= ds_control->ds_active + 3; - void *new_action= my_realloc(ds_control->ds_action, + void *new_action= my_realloc(PSI_NOT_INSTRUMENTED, ds_control->ds_action, new_alloc * sizeof(st_debug_sync_action), MYF(MY_WME | MY_ALLOW_ZERO_PTR)); if (!new_action) @@ -1364,7 +1384,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) strxnmov(ds_control->ds_proc_info, sizeof(ds_control->ds_proc_info)-1, "debug sync point: ", action->sync_point.c_ptr(), NullS); old_proc_info= thd->proc_info; - thd_proc_info(thd, ds_control->ds_proc_info); + debug_sync_thd_proc_info(thd, ds_control->ds_proc_info); } /* @@ -1482,11 +1502,11 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= old_mutex; thd->mysys_var->current_cond= old_cond; - thd_proc_info(thd, old_proc_info); + debug_sync_thd_proc_info(thd, old_proc_info); mysql_mutex_unlock(&thd->mysys_var->mutex); } else - thd_proc_info(thd, old_proc_info); + debug_sync_thd_proc_info(thd, old_proc_info); } else { diff --git a/sql/derror.cc b/sql/derror.cc index 7a79833c26c..1c10bdfdd92 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -120,8 +120,9 @@ bool init_errmessage(void) all_errors+= errors_per_range[i]; if (!(original_error_messages= (const char***) - my_malloc((all_errors + MAX_ERROR_RANGES)* sizeof(void*), - MYF(MY_ZEROFILL)))) + my_malloc(PSI_NOT_INSTRUMENTED, + (all_errors + MAX_ERROR_RANGES)*sizeof(void*), + MYF(MY_ZEROFILL)))) DBUG_RETURN(TRUE); errmsgs= (const char**)(original_error_messages + MAX_ERROR_RANGES); @@ -315,7 +316,8 @@ bool read_texts(const char *file_name, const char *language, DBUG_RETURN(1); if (!(*data= (const char***) - my_malloc((size_t) ((MAX_ERROR_RANGES+1) * sizeof(char**) + + my_malloc(key_memory_errmsgs, + (size_t) ((MAX_ERROR_RANGES+1) * sizeof(char**) + MY_MAX(msg_file.text_length, msg_file.errors * 2)+ msg_file.errors * sizeof(char*)), MYF(MY_WME)))) diff --git a/sql/discover.cc b/sql/discover.cc index 3e41388ed51..e49a2a3b0c0 100644 --- a/sql/discover.cc +++ b/sql/discover.cc @@ -76,7 +76,8 @@ int readfrm(const char *name, const uchar **frmdata, size_t *len) // Read whole frm file error= 3; - if (!(read_data= (uchar*)my_malloc(read_len, MYF(MY_WME)))) + if (!(read_data= (uchar*)my_malloc(key_memory_frm_string, read_len, + MYF(MY_WME)))) goto err; if (mysql_file_read(file, read_data, read_len, MYF(MY_NABP))) { diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 5ea8300b7e4..bd457fba4fa 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -25,13 +25,13 @@ // date_add_interval, // calc_time_diff #include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone -#include "sql_acl.h" // EVENT_ACL, SUPER_ACL #include "sp.h" // load_charset, load_collation #include "events.h" #include "event_data_objects.h" #include "event_db_repository.h" #include "sp_head.h" #include "sql_show.h" // append_definer, append_identifier +#include "mysql/psi/mysql_sp.h" #ifdef WITH_WSREP #include "wsrep_trans_observer.h" #endif /* WITH_WSREP */ @@ -40,6 +40,18 @@ @{ */ +#ifdef HAVE_PSI_INTERFACE +void init_scheduler_psi_keys() +{ + const char *category= "scheduler"; + + PSI_server->register_statement(category, & Event_queue_element_for_exec::psi_info, 1); +} + +PSI_statement_info Event_queue_element_for_exec::psi_info= +{ 0, "event", 0}; +#endif + /*************************************************************************/ /** @@ -173,11 +185,13 @@ Event_creation_ctx::load_from_db(THD *thd, */ bool -Event_queue_element_for_exec::init(const LEX_CSTRING *db, const LEX_CSTRING *n) +Event_queue_element_for_exec::init(const LEX_CSTRING &db, const LEX_CSTRING &n) { - if (!(dbname.str= my_strndup(db->str, dbname.length= db->length, MYF(MY_WME)))) + if (!(dbname.str= my_strndup(key_memory_Event_queue_element_for_exec_names, + db.str, dbname.length= db.length, MYF(MY_WME)))) return TRUE; - if (!(name.str= my_strndup(n->str, name.length= n->length, MYF(MY_WME)))) + if (!(name.str= my_strndup(key_memory_Event_queue_element_for_exec_names, + n.str, name.length= n.length, MYF(MY_WME)))) { my_free(const_cast<char*>(dbname.str)); return TRUE; @@ -211,7 +225,7 @@ Event_basic::Event_basic() { DBUG_ENTER("Event_basic::Event_basic"); /* init memory root */ - init_sql_alloc(&mem_root, "Event_basic", 256, 512, MYF(0)); + init_sql_alloc(key_memory_event_basic_root, &mem_root, 256, 512, MYF(0)); dbname.str= name.str= NULL; dbname.length= name.length= 0; time_zone= NULL; @@ -1425,15 +1439,23 @@ Event_job_data::execute(THD *thd, bool drop) { Parser_state parser_state; + sql_digest_state *parent_digest= thd->m_digest; + PSI_statement_locker *parent_locker= thd->m_statement_psi; + bool res; + if (parser_state.init(thd, thd->query(), thd->query_length())) goto end; - if (parse_sql(thd, & parser_state, creation_ctx)) + thd->m_digest= NULL; + thd->m_statement_psi= NULL; + res= parse_sql(thd, & parser_state, creation_ctx); + thd->m_digest= parent_digest; + thd->m_statement_psi= parent_locker; + + if (res) { - sql_print_error("Event Scheduler: " - "%serror during compilation of %s.%s", - thd->is_fatal_error ? "fatal " : "", - (const char *) dbname.str, (const char *) name.str); + sql_print_error("Event Scheduler: %serror during compilation of %s.%s", + thd->is_fatal_error ? "fatal " : "", dbname.str, name.str); goto end; } } @@ -1456,6 +1478,9 @@ Event_job_data::execute(THD *thd, bool drop) sphead->set_creation_ctx(creation_ctx); sphead->optimize(); + sphead->m_sp_share= MYSQL_GET_SP_SHARE(SP_TYPE_EVENT, + dbname.str, static_cast<uint>(dbname.length), + name.str, static_cast<uint>(name.length)); ret= sphead->execute_procedure(thd, &empty_item_list); /* There is no pre-locking and therefore there should be no @@ -1492,7 +1517,7 @@ end: */ privilege_t saved_master_access(thd->security_ctx->master_access); - thd->security_ctx->master_access |= SUPER_ACL; + thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY; bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index e5e3e4eb087..c20a8c31425 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -30,6 +30,8 @@ class THD; class Time_zone; struct TABLE; +void init_scheduler_psi_keys(void); + class Event_queue_element_for_exec { public: @@ -37,7 +39,7 @@ public: ~Event_queue_element_for_exec(); bool - init(const LEX_CSTRING *dbname, const LEX_CSTRING *name); + init(const LEX_CSTRING &dbname, const LEX_CSTRING &name); LEX_CSTRING dbname; LEX_CSTRING name; @@ -48,6 +50,15 @@ private: /* Prevent use of these */ Event_queue_element_for_exec(const Event_queue_element_for_exec &); void operator=(Event_queue_element_for_exec &); +#ifdef HAVE_PSI_INTERFACE +public: + PSI_statement_info* get_psi_info() + { + return & psi_info; + } + + static PSI_statement_info psi_info; +#endif }; diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 6783338ab10..af43d92dea7 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -24,7 +24,6 @@ #include "sql_db.h" // get_default_db_collation #include "sql_time.h" // interval_type_to_name #include "tztime.h" // struct Time_zone -#include "sql_acl.h" // SUPER_ACL, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields #include "records.h" // init_read_record, end_read_record #include "sp_head.h" #include "event_data_objects.h" @@ -1128,7 +1127,7 @@ update_timing_fields_for_event(THD *thd, */ save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); - DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL); + DBUG_ASSERT(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY); if (open_event_table(thd, TL_WRITE, &table)) goto end; diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 6b3f5777df3..71d1d2c68ee 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -24,6 +24,7 @@ #include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone #include "log.h" // sql_print_error #include "sql_class.h" // struct THD +#include "mysql/psi/mysql_sp.h" /** @addtogroup Event_Scheduler @@ -351,6 +352,9 @@ Event_queue::drop_matching_events(THD *thd, const LEX_CSTRING *pattern, is ok. */ queue_remove(&queue, i); + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(SP_TYPE_EVENT, et->dbname.str, static_cast<uint>(et->dbname.length), + et->name.str, static_cast<uint>(et->name.length)); delete et; } else @@ -637,7 +641,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd, } if (!(*event_name= new Event_queue_element_for_exec()) || - (*event_name)->init(&top->dbname, &top->name)) + (*event_name)->init(top->dbname, top->name)) { ret= TRUE; break; diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 9a8869e2fb3..0e8e4826939 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -22,7 +22,7 @@ #include "event_queue.h" #include "event_db_repository.h" #include "sql_connect.h" // init_new_connection_handler_thread -#include "sql_acl.h" // SUPER_ACL +#include "sql_class.h" /** @addtogroup Event_Scheduler @@ -291,6 +291,15 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) DBUG_ASSERT(thd->m_digest == NULL); DBUG_ASSERT(thd->m_statement_psi == NULL); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_statement_locker_state state; + thd->m_statement_psi= MYSQL_START_STATEMENT(& state, + event->get_psi_info()->m_key, + event->dbname.str, + event->dbname.length, + thd->charset(), NULL); +#endif + thd->thread_stack= &my_stack; // remember where our stack is res= post_init_event_thread(thd); @@ -319,7 +328,10 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) job_data.definer.str, job_data.dbname.str, job_data.name.str); end: - DBUG_ASSERT(thd->m_statement_psi == NULL); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; +#endif DBUG_ASSERT(thd->m_digest == NULL); DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str, event->name.str)); @@ -405,13 +417,14 @@ Event_scheduler::start(int *err_no) Same goes for transaction access mode. Set it to read-write for this thd. */ - new_thd->security_ctx->master_access |= SUPER_ACL; + new_thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY; new_thd->variables.tx_read_only= false; new_thd->tx_read_only= false; /* This should not be marked with MY_THREAD_SPECIFIC */ scheduler_param_value= - (struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0)); + (struct scheduler_param *)my_malloc(key_memory_Event_scheduler_scheduler_param, + sizeof(struct scheduler_param), MYF(0)); scheduler_param_value->thd= new_thd; scheduler_param_value->scheduler= this; diff --git a/sql/events.cc b/sql/events.cc index 68e013adfae..3bed25e20c3 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -34,6 +34,7 @@ #include "sp_head.h" // for Stored_program_creation_ctx #include "set_var.h" #include "lock.h" // lock_object_name +#include "mysql/psi/mysql_sp.h" /** @addtogroup Event_Scheduler @@ -620,6 +621,9 @@ Events::drop_event(THD *thd, const LEX_CSTRING *dbname, /* Binlog the drop event. */ DBUG_ASSERT(thd->query() && thd->query_length()); ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(SP_TYPE_EVENT, + dbname->str, static_cast<uint>(dbname->length), name->str, static_cast<uint>(name->length)); } thd->restore_stmt_binlog_format(save_binlog_format); @@ -832,13 +836,12 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) */ if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS) { - DBUG_ASSERT(thd->lex->first_select_lex()->db.str); - if (!is_infoschema_db(&thd->lex->first_select_lex()->db) && // There is no events in I_S - check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db.str, - NULL, NULL, 0, 0)) + LEX_CSTRING *lexdb= &thd->lex->first_select_lex()->db; + DBUG_ASSERT(lexdb); + if (!is_infoschema_db(lexdb) && !is_perfschema_db(lexdb) && + check_access(thd, EVENT_ACL, lexdb->str, NULL, NULL, 0, 0)) DBUG_RETURN(1); - db= normalize_db_name(thd->lex->first_select_lex()->db.str, - db_tmp, sizeof(db_tmp)); + db= normalize_db_name(lexdb->str, db_tmp, sizeof(db_tmp)); } ret= db_repository->fill_schema_events(thd, tables, db); @@ -1028,6 +1031,8 @@ PSI_stage_info stage_waiting_on_empty_queue= { 0, "Waiting on empty queue", 0}; PSI_stage_info stage_waiting_for_next_activation= { 0, "Waiting for next activation", 0}; PSI_stage_info stage_waiting_for_scheduler_to_stop= { 0, "Waiting for the scheduler to stop", 0}; +PSI_memory_key key_memory_event_basic_root; + #ifdef HAVE_PSI_INTERFACE PSI_stage_info *all_events_stages[]= { @@ -1036,6 +1041,11 @@ PSI_stage_info *all_events_stages[]= & stage_waiting_for_scheduler_to_stop }; +static PSI_memory_info all_events_memory[]= +{ + { &key_memory_event_basic_root, "Event_basic::mem_root", PSI_FLAG_GLOBAL} +}; + static void init_events_psi_keys(void) { const char* category= "sql"; @@ -1053,6 +1063,10 @@ static void init_events_psi_keys(void) count= array_elements(all_events_stages); mysql_stage_register(category, all_events_stages, count); + count= array_elements(all_events_memory); + mysql_memory_register(category, all_events_memory, count); + + init_scheduler_psi_keys(); } #endif /* HAVE_PSI_INTERFACE */ @@ -1158,7 +1172,7 @@ Events::load_events_from_db(THD *thd) */ privilege_t saved_master_access(thd->security_ctx->master_access); - thd->security_ctx->master_access |= SUPER_ACL; + thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY; bool save_tx_read_only= thd->tx_read_only; thd->tx_read_only= false; diff --git a/sql/events.h b/sql/events.h index 9e1651c767a..2fb13d7c807 100644 --- a/sql/events.h +++ b/sql/events.h @@ -31,6 +31,8 @@ extern PSI_cond_key key_event_scheduler_COND_state; extern PSI_thread_key key_thread_event_scheduler, key_thread_event_worker; #endif /* HAVE_PSI_INTERFACE */ +extern PSI_memory_key key_memory_event_basic_root; + /* Always defined, for SHOW PROCESSLIST. */ extern PSI_stage_info stage_waiting_on_empty_queue; extern PSI_stage_info stage_waiting_for_next_activation; diff --git a/sql/field.cc b/sql/field.cc index 1ce49b0bdfa..460c26fbfd2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1013,8 +1013,15 @@ CPP_UNNAMED_NS_END Static help functions *****************************************************************************/ +/* + @brief + Create a fixed size sort key part + + @param buff buffer where values are written + @param length fixed size of the sort column +*/ -void Field::make_sort_key(uchar *buff,uint length) +void Field::make_sort_key_part(uchar *buff,uint length) { if (maybe_null()) { @@ -1029,6 +1036,62 @@ void Field::make_sort_key(uchar *buff,uint length) } +/* + @brief + Create a packed sort key part + + @param buff buffer where values are written + @param sort_field sort column structure + + @retval + length of the bytes written, does not include the NULL bytes +*/ +uint +Field::make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + sort_string(buff, sort_field->original_length); + return sort_field->original_length; +} + + +uint +Field_longstr::make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + uchar *end= pack_sort_string(buff, sort_field); + return static_cast<int>(end-buff); +} + + +uchar* +Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field) +{ + String buf; + val_str(&buf, &buf); + return to + sort_field->pack_sort_string(to, buf.lex_cstring(), + field_charset()); +} + + /** @brief Determine the relative position of the field value in a numeric interval @@ -5395,29 +5458,6 @@ static longlong read_native(const uchar *from, uint bytes) } #endif -static void store_lowendian(ulonglong num, uchar *to, uint bytes) -{ - switch(bytes) { - case 1: *to= (uchar)num; break; - case 2: int2store(to, num); break; - case 3: int3store(to, num); break; - case 4: int4store(to, num); break; - case 8: int8store(to, num); break; - default: DBUG_ASSERT(0); - } -} - -static longlong read_lowendian(const uchar *from, uint bytes) -{ - switch(bytes) { - case 1: return from[0]; - case 2: return uint2korr(from); - case 3: return uint3korr(from); - case 4: return uint4korr(from); - case 8: return sint8korr(from); - default: DBUG_ASSERT(0); return 0; - } -} void Field_timestamp_hires::store_TIMEVAL(const timeval &tv) { @@ -7030,6 +7070,27 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, } +/* + This is JSON specific. + We should eventually add Field_json_varchar and Field_json_blob + and move make_send_field() to the new classes. +*/ +void Field_longstr::make_send_field(Send_field *field) +{ + Field_str::make_send_field(field); + if (check_constraint) + { + /* + Append the format that is implicitly implied by the CHECK CONSTRAINT. + For example: + CREATE TABLE t1 (js longtext DEFAULT NULL CHECK (json_valid(a))); + SELECT j FROM t1; + will add "format=json" to the extended type info metadata for t1.js. + */ + check_constraint->expr->set_format_by_check_constraint(field); + } +} + /* Copy a string and fill with space */ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) @@ -8013,7 +8074,7 @@ int Field_longstr::compress(char *to, uint to_length, max_length < length) { set_if_smaller(max_length, static_cast<ulonglong>(mbmaxlen()) * length + 1); - if (!(buf= (char*) my_malloc(max_length, MYF(MY_WME)))) + if (!(buf= (char*) my_malloc(PSI_INSTRUMENT_ME, max_length, MYF(MY_WME)))) { *out_length= 0; return -1; @@ -8526,8 +8587,15 @@ Binlog_type_info Field_blob::binlog_type_info() const uint32 Field_blob::sort_length() const { - return (uint32) (get_thd()->variables.max_sort_length + - (field_charset() == &my_charset_bin ? 0 : packlength)); + return packlength == 4 ? + UINT_MAX32 : + (uint32) field_length + sort_suffix_length(); +} + + +uint32 Field_blob::sort_suffix_length() const +{ + return field_charset() == &my_charset_bin ? packlength : 0; } diff --git a/sql/field.h b/sql/field.h index 4a8eec35b05..425f9f5292c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -51,6 +51,8 @@ class Table_ident; class SEL_ARG; class RANGE_OPT_PARAM; struct KEY_PART; +struct SORT_FIELD; +struct SORT_FIELD_ATTR; enum enum_check_fields { @@ -1075,6 +1077,12 @@ public: virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } + /* + sort_suffix_length() return the length bytes needed to store the length + for binary charset + */ + virtual uint32 sort_suffix_length() const { return 0; } + /* Get the number bytes occupied by the value in the field. CHAR values are stripped of trailing spaces. @@ -1410,7 +1418,18 @@ public: return bytes; } - void make_sort_key(uchar *buff, uint length); + /* + Create mem-comparable sort key part for a sort key + */ + void make_sort_key_part(uchar *buff, uint length); + + /* + create a compact sort key which can be compared with a comparison + function. They are called packed sort keys + */ + virtual uint make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field); + virtual void make_send_field(Send_field *); virtual void sort_string(uchar *buff,uint length)=0; virtual bool optimize_range(uint idx, uint part) const; @@ -1527,7 +1546,7 @@ public: { return length;} virtual uint max_packed_col_length(uint max_length) { return max_length;} - virtual bool is_packable() { return false; } + virtual bool is_packable() const { return false; } uint offset(const uchar *record) const { @@ -2120,11 +2139,12 @@ public: {} enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, - const Conv_param ¶m) const; - int store_decimal(const my_decimal *d); - uint32 max_data_length() const; + const Conv_param ¶m) const override; + int store_decimal(const my_decimal *d) override; + uint32 max_data_length() const override; + void make_send_field(Send_field *) override; - bool is_varchar_and_in_write_set() const + bool is_varchar_and_in_write_set() const override { DBUG_ASSERT(table && table->write_set); return bitmap_is_set(table->write_set, field_index); @@ -2132,15 +2152,18 @@ public: bool match_collation_to_optimize_range() const { return true; } bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const; + const Item *item) const override; bool can_optimize_hash_join(const Item_bool_func *cond, - const Item *item) const; + const Item *item) const override; bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const; + const Item *const_item) const override; bool can_optimize_range(const Item_bool_func *cond, const Item *item, - bool is_eq_func) const; - bool is_packable() { return true; } + bool is_eq_func) const override; + bool is_packable() const override { return true; } + uint make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field)override; + uchar* pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field); }; /* base class for float and double and decimal (old one) */ @@ -4042,8 +4065,11 @@ public: uint32 key_length() const override { return (uint32) field_length; } uint32 sort_length() const override { - return (uint32) field_length + (field_charset() == &my_charset_bin ? - length_bytes : 0); + return (uint32) field_length + sort_suffix_length(); + } + virtual uint32 sort_suffix_length() const override + { + return (field_charset() == &my_charset_bin ? length_bytes : 0); } Copy_func *get_copy_func(const Field *from) const override; bool memcpy_field_possible(const Field *from) const override; @@ -4187,6 +4213,30 @@ static inline longlong read_bigendian(const uchar *from, uint bytes) } } +static inline void store_lowendian(ulonglong num, uchar *to, uint bytes) +{ + switch(bytes) { + case 1: *to= (uchar)num; break; + case 2: int2store(to, num); break; + case 3: int3store(to, num); break; + case 4: int4store(to, num); break; + case 8: int8store(to, num); break; + default: DBUG_ASSERT(0); + } +} + +static inline longlong read_lowendian(const uchar *from, uint bytes) +{ + switch(bytes) { + case 1: return from[0]; + case 2: return uint2korr(from); + case 3: return uint3korr(from); + case 4: return uint4korr(from); + case 8: return sint8korr(from); + default: DBUG_ASSERT(0); return 0; + } +} + extern LEX_CSTRING temp_lex_str; @@ -4353,6 +4403,7 @@ public: { return (uint32) (packlength); } uint row_pack_length() const override { return pack_length_no_ptr(); } uint32 sort_length() const override; + uint32 sort_suffix_length() const override; uint32 value_length() override { return get_length(); } virtual uint32 max_data_length() const override { @@ -5461,7 +5512,8 @@ public: */ class Send_field :public Sql_alloc, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Send_field_extended_metadata { public: LEX_CSTRING db_name; diff --git a/sql/filesort.cc b/sql/filesort.cc index 763f9f59246..1e19d492220 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -48,13 +48,18 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, ha_rows *found_rows); static bool write_keys(Sort_param *param, SORT_INFO *fs_info, uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile); -static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos); +static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos, + bool using_packed_sortkeys= false); +static uint make_sortkey(Sort_param *param, uchar *to); +static uint make_packed_sortkey(Sort_param *param, uchar *to); + static void register_used_fields(Sort_param *param); static bool save_index(Sort_param *param, uint count, SORT_INFO *table_sort); static uint suffix_length(ulong string_length); -static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, - bool *multi_byte_charset); +static uint sortlength(THD *thd, Sort_keys *sortorder, + bool *multi_byte_charset, + bool *allow_packing_for_sortkeys); static Addon_fields *get_addon_fields(TABLE *table, uint sortlength, uint *addon_length, uint *m_packable_length); @@ -63,6 +68,31 @@ static bool check_if_pq_applicable(Sort_param *param, SORT_INFO *info, TABLE *table, ha_rows records, size_t memory_available); +static void store_key_part_length(uint32 num, uchar *to, uint bytes) +{ + switch(bytes) { + case 1: *to= (uchar)num; break; + case 2: int2store(to, num); break; + case 3: int3store(to, num); break; + case 4: int4store(to, num); break; + default: DBUG_ASSERT(0); + } +} + + +static uint32 read_keypart_length(const uchar *from, uint bytes) +{ + switch(bytes) { + case 1: return from[0]; + case 2: return uint2korr(from); + case 3: return uint3korr(from); + case 4: return uint4korr(from); + default: DBUG_ASSERT(0); return 0; + } +} + + +// @param sortlen [Maximum] length of the sort key void Sort_param::init_for_filesort(uint sortlen, TABLE *table, ha_rows maxrows, bool sort_positions) { @@ -108,7 +138,7 @@ void Sort_param::try_to_pack_addons(ulong max_length_for_sort_data) if (!Addon_fields::can_pack_addon_fields(res_length)) return; - const uint sz= Addon_fields::size_of_length_field;; + const uint sz= Addon_fields::size_of_length_field; if (rec_length + sz > max_length_for_sort_data) return; @@ -125,6 +155,7 @@ void Sort_param::try_to_pack_addons(ulong max_length_for_sort_data) addon_fields->set_using_packed_addons(true); m_using_packed_addons= true; + m_packed_format= true; addon_length+= sz; res_length+= sz; @@ -171,18 +202,21 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, ha_rows num_rows= HA_POS_ERROR; IO_CACHE tempfile, buffpek_pointers, *outfile; Sort_param param; - bool multi_byte_charset; + bool multi_byte_charset, allow_packing_for_sortkeys; Bounded_queue<uchar, uchar> pq; SQL_SELECT *const select= filesort->select; ha_rows max_rows= filesort->limit; uint s_length= 0; + Sort_keys *sort_keys; DBUG_ENTER("filesort"); - if (!(s_length= filesort->make_sortorder(thd, join, first_table_bit))) + if (!(sort_keys= filesort->make_sortorder(thd, join, first_table_bit))) DBUG_RETURN(NULL); /* purecov: inspected */ - DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder,s_length);); + s_length= static_cast<uint>(sort_keys->size()); + + DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder, s_length);); #ifdef SKIP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif @@ -215,16 +249,14 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, error= 1; sort->found_rows= HA_POS_ERROR; - param.init_for_filesort(sortlength(thd, filesort->sortorder, s_length, - &multi_byte_charset), - table, max_rows, filesort->sort_positions); + param.sort_keys= sort_keys; + uint sort_len= sortlength(thd, sort_keys, &multi_byte_charset, + &allow_packing_for_sortkeys); - sort->addon_fields= param.addon_fields; + param.init_for_filesort(sort_len, table, max_rows, filesort->sort_positions); - if (multi_byte_charset && - !(param.tmp_buffer= (char*) my_malloc(param.sort_length, - MYF(MY_WME | MY_THREAD_SPECIFIC)))) - goto err; + sort->addon_fields= param.addon_fields; + sort->sort_keys= param.sort_keys; if (select && select->quick) thd->inc_status_sort_range(); @@ -245,6 +277,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, tracker->incr_pq_used(); param.using_pq= true; const size_t compare_length= param.sort_length; + DBUG_ASSERT(param.using_packed_sortkeys() == false); /* For PQ queries (with limit) we know exactly how many pointers/records we have in the buffer, so to simplify things, we initialize @@ -271,9 +304,19 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, { DBUG_PRINT("info", ("filesort PQ is not applicable")); + if (allow_packing_for_sortkeys) + param.try_to_pack_sortkeys(); + param.try_to_pack_addons(thd->variables.max_length_for_sort_data); + tracker->report_sort_keys_format(param.using_packed_sortkeys()); param.using_pq= false; + if ((multi_byte_charset || param.using_packed_sortkeys()) && + !(param.tmp_buffer= (char*) my_malloc(key_memory_Sort_param_tmp_buffer, param.sort_length, + MYF(MY_WME | MY_THREAD_SPECIFIC)))) + goto err; + + size_t min_sort_memory= MY_MAX(MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2); set_if_bigger(min_sort_memory, sizeof(Merge_chunk*)*MERGEBUFF2); @@ -298,6 +341,12 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, tracker->report_sort_buffer_size(sort->sort_buffer_size()); } + if (param.using_addon_fields()) + { + // report information whether addon fields are packed or not + tracker->report_addon_fields_format(param.using_packed_addons()); + } + if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME))) goto err; @@ -479,24 +528,42 @@ void Filesort::cleanup() } -uint Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit) +/* + Create the Sort_keys array and fill the sort_keys[i]->{item|field}. + + This indicates which field/item values will be used as sort keys. + Attributes like lengths are not filled yet. +*/ + +Sort_keys* +Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit) { uint count; SORT_FIELD *sort,*pos; ORDER *ord; DBUG_ENTER("make_sortorder"); - count=0; for (ord = order; ord; ord= ord->next) count++; - if (!sortorder) - sortorder= (SORT_FIELD*) thd->alloc(sizeof(SORT_FIELD) * (count + 1)); + + if (sortorder) + DBUG_RETURN(sort_keys); + + DBUG_ASSERT(sort_keys == NULL); + + sortorder= (SORT_FIELD*) thd->alloc(sizeof(SORT_FIELD) * count); pos= sort= sortorder; if (!pos) DBUG_RETURN(0); + sort_keys= new Sort_keys(sortorder, count); + + if (!sort_keys) + DBUG_RETURN(0); + + pos= sort_keys->begin(); for (ord= order; ord; ord= ord->next, pos++) { Item *first= ord->item[0]; @@ -537,7 +604,7 @@ uint Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit) pos->reverse= (ord->direction == ORDER::ORDER_DESC); DBUG_ASSERT(pos->field != NULL || pos->item != NULL); } - DBUG_RETURN(count); + DBUG_RETURN(sort_keys); } @@ -552,7 +619,8 @@ static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count, if (count > UINT_MAX/sizeof(Merge_chunk)) return 0; /* sizeof(BUFFPEK)*count will overflow */ if (!tmp) - tmp= (uchar *)my_malloc(length, MYF(MY_WME | MY_THREAD_SPECIFIC)); + tmp= (uchar *)my_malloc(key_memory_Filesort_info_merge, length, + MYF(MY_WME | MY_THREAD_SPECIFIC)); if (tmp) { if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) || @@ -746,7 +814,7 @@ static void dbug_print_record(TABLE *table, bool print_rowid) static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, SORT_INFO *fs_info, - IO_CACHE *buffpek_pointers, + IO_CACHE *buffpek_pointers, IO_CACHE *tempfile, Bounded_queue<uchar, uchar> *pq, ha_rows *found_rows) @@ -759,7 +827,9 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, MY_BITMAP *save_read_set, *save_write_set; Item *sort_cond; ha_rows num_records= 0; - const bool packed_addon_fields= param->using_packed_addons(); + const bool packed_format= param->is_packed_format(); + const bool using_packed_sortkeys= param->using_packed_sortkeys(); + DBUG_ENTER("find_all_keys"); DBUG_PRINT("info",("using: %s", (select ? select->quick ? "ranges" : "where": @@ -815,6 +885,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, } DEBUG_SYNC(thd, "after_index_merge_phase1"); + for (;;) { if (quick_select) @@ -882,8 +953,9 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, fs_info->init_next_record_pointer(); uchar *start_of_rec= fs_info->get_next_record_pointer(); - const uint rec_sz= make_sortkey(param, start_of_rec, ref_pos); - if (packed_addon_fields && rec_sz != param->rec_length) + const uint rec_sz= make_sortkey(param, start_of_rec, + ref_pos, using_packed_sortkeys); + if (packed_format && rec_sz != param->rec_length) fs_info->adjust_next_record_pointer(rec_sz); idx++; } @@ -964,12 +1036,9 @@ static bool write_keys(Sort_param *param, SORT_INFO *fs_info, uint count, IO_CACHE *buffpek_pointers, IO_CACHE *tempfile) { - size_t rec_length; Merge_chunk buffpek; DBUG_ENTER("write_keys"); - rec_length= param->rec_length; - fs_info->sort_buffer(param, count); if (!my_b_inited(tempfile) && @@ -985,19 +1054,12 @@ write_keys(Sort_param *param, SORT_INFO *fs_info, uint count, count=(uint) param->max_rows; /* purecov: inspected */ buffpek.set_rowcount(static_cast<ha_rows>(count)); - const bool packed_addon_fields= param->using_packed_addons(); for (uint ix= 0; ix < count; ++ix) { uchar *record= fs_info->get_sorted_record(ix); - if (packed_addon_fields) - { - rec_length= param->sort_length + - Addon_fields::read_addon_length(record + param->sort_length); - } - else - rec_length= param->rec_length; - if (my_b_write(tempfile, record, rec_length)) + + if (my_b_write(tempfile, record, param->get_record_length(record))) DBUG_RETURN(1); /* purecov: inspected */ } @@ -1010,10 +1072,9 @@ write_keys(Sort_param *param, SORT_INFO *fs_info, uint count, /** - Store length as suffix in high-byte-first order. + Store length in high-byte-first order. */ - -static inline void store_length(uchar *to, uint length, uint pack_length) +void store_length(uchar *to, uint length, uint pack_length) { switch (pack_length) { case 1: @@ -1033,9 +1094,9 @@ static inline void store_length(uchar *to, uint length, uint pack_length) void -Type_handler_string_result::make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const +Type_handler_string_result::make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const { CHARSET_INFO *cs= item->collation.collation; bool maybe_null= item->maybe_null; @@ -1105,9 +1166,9 @@ Type_handler_string_result::make_sort_key(uchar *to, Item *item, void -Type_handler_int_result::make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const +Type_handler_int_result::make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const { longlong value= item->val_int_result(); make_sort_key_longlong(to, item->maybe_null, item->null_value, @@ -1116,7 +1177,7 @@ Type_handler_int_result::make_sort_key(uchar *to, Item *item, void -Type_handler_temporal_result::make_sort_key(uchar *to, Item *item, +Type_handler_temporal_result::make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const { @@ -1138,7 +1199,7 @@ Type_handler_temporal_result::make_sort_key(uchar *to, Item *item, void -Type_handler_timestamp_common::make_sort_key(uchar *to, Item *item, +Type_handler_timestamp_common::make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const { @@ -1171,6 +1232,24 @@ Type_handler_timestamp_common::make_sort_key(uchar *to, Item *item, void +Type_handler::store_sort_key_longlong(uchar *to, bool unsigned_flag, + longlong value) const +{ + to[7]= (uchar) value; + to[6]= (uchar) (value >> 8); + to[5]= (uchar) (value >> 16); + to[4]= (uchar) (value >> 24); + to[3]= (uchar) (value >> 32); + to[2]= (uchar) (value >> 40); + to[1]= (uchar) (value >> 48); + if (unsigned_flag) /* Fix sign */ + to[0]= (uchar) (value >> 56); + else + to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */ +} + + +void Type_handler::make_sort_key_longlong(uchar *to, bool maybe_null, bool null_value, @@ -1187,24 +1266,35 @@ Type_handler::make_sort_key_longlong(uchar *to, } *to++= 1; } - to[7]= (uchar) value; - to[6]= (uchar) (value >> 8); - to[5]= (uchar) (value >> 16); - to[4]= (uchar) (value >> 24); - to[3]= (uchar) (value >> 32); - to[2]= (uchar) (value >> 40); - to[1]= (uchar) (value >> 48); - if (unsigned_flag) /* Fix sign */ - to[0]= (uchar) (value >> 56); - else - to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */ + store_sort_key_longlong(to, unsigned_flag, value); +} + + +uint +Type_handler::make_packed_sort_key_longlong(uchar *to, bool maybe_null, + bool null_value, bool unsigned_flag, + longlong value, + const SORT_FIELD_ATTR *sort_field) const +{ + if (maybe_null) + { + if (null_value) + { + *to++= 0; + return 0; + } + *to++= 1; + } + store_sort_key_longlong(to, unsigned_flag, value); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; } void -Type_handler_decimal_result::make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const +Type_handler_decimal_result::make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const { my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf); if (item->maybe_null) @@ -1222,9 +1312,9 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item, void -Type_handler_real_result::make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const +Type_handler_real_result::make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const { double value= item->val_result(); if (item->maybe_null) @@ -1242,48 +1332,14 @@ Type_handler_real_result::make_sort_key(uchar *to, Item *item, /** Make a sort-key from record. */ -static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos) +static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos, + bool using_packed_sortkeys) { - Field *field; - SORT_FIELD *sort_field; - uint length; uchar *orig_to= to; - for (sort_field=param->local_sortorder.begin() ; - sort_field != param->local_sortorder.end() ; - sort_field++) - { - bool maybe_null=0; - if ((field=sort_field->field)) - { // Field - field->make_sort_key(to, sort_field->length); - if ((maybe_null = field->maybe_null())) - to++; - } - else - { // Item - sort_field->item->type_handler()->make_sort_key(to, sort_field->item, - sort_field, param); - if ((maybe_null= sort_field->item->maybe_null)) - to++; - } - if (sort_field->reverse) - { /* Revers key */ - if (maybe_null && (to[-1]= !to[-1])) - { - to+= sort_field->length; // don't waste the time reversing all 0's - continue; - } - length=sort_field->length; - while (length--) - { - *to = (uchar) (~ *to); - to++; - } - } - else - to+= sort_field->length; - } + to+= using_packed_sortkeys ? + make_packed_sortkey(param, to) : + make_sortkey(param, to); if (param->using_addon_fields()) { @@ -1379,7 +1435,7 @@ static void register_used_fields(Sort_param *param) static bool save_index(Sort_param *param, uint count, SORT_INFO *table_sort) { - uint offset,res_length; + uint offset,res_length, length; uchar *to; DBUG_ENTER("save_index"); DBUG_ASSERT(table_sort->record_pointers == 0); @@ -1393,16 +1449,21 @@ static bool save_index(Sort_param *param, uint count, DBUG_RETURN(0); } + bool using_packed_sortkeys= param->using_packed_sortkeys(); res_length= param->res_length; offset= param->rec_length-res_length; if (!(to= table_sort->record_pointers= - (uchar*) my_malloc(res_length*count, - MYF(MY_WME | MY_THREAD_SPECIFIC)))) + (uchar*) my_malloc(key_memory_Filesort_info_record_pointers, + res_length*count, MYF(MY_WME | MY_THREAD_SPECIFIC)))) DBUG_RETURN(1); /* purecov: inspected */ for (uint ix= 0; ix < count; ++ix) { uchar *record= table_sort->get_sorted_record(ix); - memcpy(to, record + offset, res_length); + + length= using_packed_sortkeys ? + Sort_keys::read_sortkey_length(record) : offset; + + memcpy(to, record + length, res_length); to+= res_length; } DBUG_RETURN(0); @@ -1605,7 +1666,7 @@ cleanup: */ ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek, - Sort_param *param) + Sort_param *param, bool packed_format) { ha_rows count; uint rec_length= param->rec_length; @@ -1613,7 +1674,7 @@ ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek, if ((count= MY_MIN(buffpek->max_keys(),buffpek->rowcount()))) { size_t bytes_to_read; - if (param->using_packed_addons()) + if (packed_format) { count= buffpek->rowcount(); bytes_to_read= MY_MIN(buffpek->buffer_size(), @@ -1628,26 +1689,43 @@ ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek, return ((ulong) -1); size_t num_bytes_read; - if (param->using_packed_addons()) + + if (packed_format) { /* The last record read is most likely not complete here. We need to loop through all the records, reading the length fields, and then "chop off" the final incomplete record. - */ + */ uchar *record= buffpek->buffer_start(); uint ix= 0; + uint size_of_addon_length= param->using_packed_addons() ? + Addon_fields::size_of_length_field : 0; + + uint size_of_sort_length= param->using_packed_sortkeys() ? + Sort_keys::size_of_length_field : 0; + for (; ix < count; ++ix) { - if (record + param->sort_length + Addon_fields::size_of_length_field > + if (record + size_of_sort_length > buffpek->buffer_end()) + break; + uint sort_length= param->using_packed_sortkeys() ? + Sort_keys::read_sortkey_length(record) : + param->sort_length; + + DBUG_ASSERT(sort_length <= param->sort_length); + + if (record + sort_length + size_of_addon_length > buffpek->buffer_end()) break; // Incomplete record. - uchar *plen= record + param->sort_length; - uint res_length= Addon_fields::read_addon_length(plen); + + uchar *plen= record + sort_length; + uint res_length= param->get_result_length(plen); if (plen + res_length > buffpek->buffer_end()) break; // Incomplete record. DBUG_ASSERT(res_length > 0); - record+= param->sort_length; + DBUG_ASSERT(sort_length + res_length <= param->rec_length); + record+= sort_length; record+= res_length; } DBUG_ASSERT(ix > 0); @@ -1704,7 +1782,10 @@ void reuse_freed_buff(QUEUE *queue, Merge_chunk *reuse, uint key_length) @param lastbuff OUT Store here BUFFPEK describing data written to to_file @param Fb First element in source BUFFPEKs array @param Tb Last element in source BUFFPEKs array - @param flag + @param flag 0 <=> write {sort_key, addon_fields} pairs as further + sorting will be performed + 1 <=> write just addon_fields as this is the final + merge pass @retval 0 OK @@ -1748,6 +1829,11 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, (flag && min_dupl_count ? sizeof(dupl_count) : 0)-res_length); uint wr_len= flag ? res_length : rec_length; uint wr_offset= flag ? offset : 0; + + const bool using_packed_sortkeys= param->using_packed_sortkeys(); + bool offset_for_packing= (flag == 1 && using_packed_sortkeys); + const bool packed_format= param->is_packed_format(); + maxcount= (ulong) (param->max_keys_per_buffer/((uint) (Tb-Fb) +1)); to_start_filepos= my_b_tell(to_file); strpos= sort_buffer.array(); @@ -1762,8 +1848,8 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, } else { - cmp= get_ptr_compare(sort_length); - first_cmp_arg= (void*) &sort_length; + cmp= param->get_compare_function(); + first_cmp_arg= param->get_compare_argument(&sort_length); } if (unlikely(init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(Merge_chunk,m_current_key), 0, @@ -1775,7 +1861,7 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, strpos + (sort_buffer.size()/((uint) (Tb-Fb) +1))); buffpek->set_max_keys(maxcount); - bytes_read= read_to_buffer(from_file, buffpek, param); + bytes_read= read_to_buffer(from_file, buffpek, param, packed_format); if (unlikely(bytes_read == (ulong) -1)) goto err; /* purecov: inspected */ strpos+= bytes_read; @@ -1802,7 +1888,7 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, if (buffpek->mem_count() == 0) { if (unlikely(!(bytes_read= read_to_buffer(from_file, buffpek, - param)))) + param, packed_format)))) { (void) queue_remove_top(&queue); reuse_freed_buff(&queue, buffpek, rec_length); @@ -1860,7 +1946,11 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, */ if (!check_dupl_count || dupl_count >= min_dupl_count) { - if (my_b_write(to_file, src + wr_offset, bytes_to_write)) + if(my_b_write(to_file, + src + (offset_for_packing ? + rec_length - res_length : // sort length + wr_offset), + bytes_to_write)) goto err; /* purecov: inspected */ } if (cmp) @@ -1883,7 +1973,7 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, if (buffpek->mem_count() == 0) { if (unlikely(!(bytes_read= read_to_buffer(from_file, buffpek, - param)))) + param, packed_format)))) { (void) queue_remove_top(&queue); reuse_freed_buff(&queue, buffpek, rec_length); @@ -1943,7 +2033,8 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, max_rows-= buffpek->mem_count(); for (uint ix= 0; ix < buffpek->mem_count(); ++ix) { - param->get_rec_and_res_len(buffpek->current_key(), + uchar *src= buffpek->current_key(); + param->get_rec_and_res_len(src, &rec_length, &res_length); const uint bytes_to_write= (flag == 0) ? rec_length : res_length; if (check_dupl_count) @@ -1954,15 +2045,18 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file, if (dupl_count < min_dupl_count) continue; } - if (my_b_write(to_file, buffpek->current_key() + wr_offset, - bytes_to_write)) + if(my_b_write(to_file, + src + (offset_for_packing ? + rec_length - res_length : // sort length + wr_offset), + bytes_to_write)) goto err; buffpek->advance_current_key(rec_length); } } while (likely(!(error= - (bytes_read= read_to_buffer(from_file, buffpek, - param)) == (ulong) -1)) && + (bytes_read= read_to_buffer(from_file, buffpek, param, + packed_format)) == (ulong) -1)) && bytes_read != 0); end: @@ -2007,13 +2101,14 @@ static uint suffix_length(ulong string_length) void -Type_handler_string_result::sortlength(THD *thd, +Type_handler_string_result::sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *sortorder) const { CHARSET_INFO *cs; sortorder->length= item->max_length; - set_if_smaller(sortorder->length, thd->variables.max_sort_length); + sortorder->original_length= item->max_length; + if (use_strnxfrm((cs= item->collation.collation))) { sortorder->length= (uint) cs->strnxfrmlen(sortorder->length); @@ -2023,54 +2118,57 @@ Type_handler_string_result::sortlength(THD *thd, /* Store length last to be able to sort blob/varbinary */ sortorder->suffix_length= suffix_length(sortorder->length); sortorder->length+= sortorder->suffix_length; + sortorder->original_length+= sortorder->suffix_length; } } void -Type_handler_temporal_result::sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *sortorder) const +Type_handler_temporal_result::sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *sortorder) const { - sortorder->length= 8; // Sizof intern longlong + sortorder->original_length= sortorder->length= 8; // Sizof intern longlong } void -Type_handler_timestamp_common::sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *sortorder) const +Type_handler_timestamp_common::sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *sortorder) const { sortorder->length= my_timestamp_binary_length(item->decimals); + sortorder->original_length= sortorder->length; } void -Type_handler_int_result::sortlength(THD *thd, +Type_handler_int_result::sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *sortorder) const { - sortorder->length= 8; // Sizof intern longlong + sortorder->original_length= sortorder->length= 8; // Sizof intern longlong } void -Type_handler_real_result::sortlength(THD *thd, +Type_handler_real_result::sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *sortorder) const { - sortorder->length= sizeof(double); + sortorder->original_length= sortorder->length= sizeof(double); } void -Type_handler_decimal_result::sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *sortorder) const +Type_handler_decimal_result::sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *sortorder) const { sortorder->length= my_decimal_get_binary_size(item->max_length - (item->decimals ? 1 : 0), item->decimals); + sortorder->original_length= sortorder->length; } @@ -2082,54 +2180,100 @@ Type_handler_decimal_result::sortlength(THD *thd, @param s_length Number of items to sort @param[out] multi_byte_charset Set to 1 if we are using multi-byte charset (In which case we have to use strxnfrm()) + @param allow_packing_for_sortkeys [out] set to false if packing sort keys is not + allowed @note - sortorder->length is updated for each sort item. + * sortorder->length and other members are updated for each sort item. + * TODO what is the meaning of this value if some fields are using packing while + others are not? @return Total length of sort buffer in bytes */ static uint -sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, - bool *multi_byte_charset) +sortlength(THD *thd, Sort_keys *sort_keys, bool *multi_byte_charset, + bool *allow_packing_for_sortkeys) { uint length; *multi_byte_charset= 0; + *allow_packing_for_sortkeys= true; + bool allow_packing_for_keys= true; length=0; - for (; s_length-- ; sortorder++) + uint nullable_cols=0; + + for (SORT_FIELD *sortorder= sort_keys->begin(); + sortorder != sort_keys->end(); + sortorder++) { sortorder->suffix_length= 0; + sortorder->length_bytes= 0; if (sortorder->field) { + Field *field= sortorder->field; CHARSET_INFO *cs= sortorder->field->sort_charset(); sortorder->length= sortorder->field->sort_length(); + sortorder->suffix_length= sortorder->field->sort_suffix_length(); + sortorder->original_length= sortorder->length; + sortorder->type= field->is_packable() ? + SORT_FIELD_ATTR::VARIABLE_SIZE : + SORT_FIELD_ATTR::FIXED_SIZE; + sortorder->cs= cs; + if (use_strnxfrm((cs=sortorder->field->sort_charset()))) { *multi_byte_charset= true; sortorder->length= (uint) cs->strnxfrmlen(sortorder->length); } - if (sortorder->field->maybe_null()) - length++; // Place for NULL marker + if (sortorder->is_variable_sized() && allow_packing_for_keys) + { + allow_packing_for_keys= sortorder->check_if_packing_possible(thd); + sortorder->length_bytes= + number_storage_requirement(MY_MIN(sortorder->original_length, + thd->variables.max_sort_length)); + } + + if ((sortorder->maybe_null= sortorder->field->maybe_null())) + nullable_cols++; // Place for NULL marker } else { - sortorder->item->type_handler()->sortlength(thd, sortorder->item, - sortorder); - if (use_strnxfrm(sortorder->item->collation.collation)) + CHARSET_INFO *cs; + sortorder->item->type_handler()->sort_length(thd, sortorder->item, + sortorder); + sortorder->type= sortorder->item->type_handler()->is_packable() ? + SORT_FIELD_ATTR::VARIABLE_SIZE : + SORT_FIELD_ATTR::FIXED_SIZE; + if (use_strnxfrm((cs=sortorder->item->collation.collation))) { *multi_byte_charset= true; } - if (sortorder->item->maybe_null) - length++; // Place for NULL marker + sortorder->cs= cs; + if (sortorder->is_variable_sized() && allow_packing_for_keys) + { + allow_packing_for_keys= sortorder->check_if_packing_possible(thd); + sortorder->length_bytes= + number_storage_requirement(MY_MIN(sortorder->original_length, + thd->variables.max_sort_length)); + } + + if ((sortorder->maybe_null= sortorder->item->maybe_null)) + nullable_cols++; // Place for NULL marker } set_if_smaller(sortorder->length, thd->variables.max_sort_length); + set_if_smaller(sortorder->original_length, thd->variables.max_sort_length); length+=sortorder->length; + + sort_keys->increment_size_of_packable_fields(sortorder->length_bytes); + sort_keys->increment_original_sort_length(sortorder->original_length); } - sortorder->field= NULL; // end marker + // add bytes for nullable_cols + sort_keys->increment_original_sort_length(nullable_cols); + *allow_packing_for_sortkeys= allow_packing_for_keys; DBUG_PRINT("info",("sort_length: %d",length)); - return length; + return length + nullable_cols; } @@ -2237,7 +2381,7 @@ get_addon_fields(TABLE *table, uint sortlength, if (!filesort_use_addons(table, sortlength, &length, &fields, &null_fields, &packable_length) || - !(my_multi_malloc(MYF(MY_WME | MY_THREAD_SPECIFIC), + !(my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_THREAD_SPECIFIC), &raw_mem, sizeof(Addon_fields), &raw_mem_addon_field, sizeof(SORT_ADDON_FIELD) * fields, @@ -2283,23 +2427,6 @@ get_addon_fields(TABLE *table, uint sortlength, } -/** - Copy (unpack) values appended to sorted fields from a buffer back to - their regular positions specified by the Field::ptr pointers. - - @param addon_field Array of descriptors for appended fields - @param buff Buffer which to unpack the value from - - @note - The function is supposed to be used only as a callback function - when getting field values for the sorted result set. - - @return - void. -*/ - - - /* ** functions to change a double or float to a sortable string ** The following should work for IEEE @@ -2359,6 +2486,14 @@ void SORT_INFO::free_addon_buff() addon_fields->free_addon_buff(); } +/* + Check if packed sortkeys are used or not +*/ +bool SORT_INFO::using_packed_sortkeys() +{ + return sort_keys != NULL && sort_keys->using_packed_sortkeys(); +} + /** Free SORT_INFO */ @@ -2369,3 +2504,561 @@ SORT_INFO::~SORT_INFO() free_data(); DBUG_VOID_RETURN; } + + +void Sort_param::try_to_pack_sortkeys() +{ + #ifdef WITHOUT_PACKED_SORT_KEYS + return; + #endif + + uint size_of_packable_fields= sort_keys->get_size_of_packable_fields(); + + /* + Disable packing when all fields are fixed-size fields. + */ + if (size_of_packable_fields == 0) + return; + + const uint sz= Sort_keys::size_of_length_field; + uint sort_len= sort_keys->get_sort_length(); + + /* + Heuristic introduced, skip packing sort keys if saving less than 128 bytes + */ + + if (sort_len < 128 + sz + size_of_packable_fields) + return; + + sort_keys->set_using_packed_sortkeys(true); + m_packed_format= true; + m_using_packed_sortkeys= true; + sort_length= sort_len + sz + size_of_packable_fields + + (using_addon_fields() ? 0 : res_length); + /* Only the record length needs to be updated, the res_length does not need + to be updated + */ + rec_length= sort_length + addon_length; +} + + +uint +Type_handler_string_result::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + CHARSET_INFO *cs= item->collation.collation; + bool maybe_null= item->maybe_null; + + if (maybe_null) + *to++= 1; + + String tmp(param->tmp_buffer, param->sort_length, cs); + String *res= item->str_result(&tmp); + if (!res) + { + if (maybe_null) + { + *(to-1)= 0; + return 0; + } + else + { + /* purecov: begin deadcode */ + /* + This should only happen during extreme conditions if we run out + of memory or have an item marked not null when it can be null. + This code is here mainly to avoid a hard crash in this case. + */ + DBUG_ASSERT(0); + DBUG_PRINT("warning", + ("Got null on something that shouldn't be null")); + memset(to, 0, sort_field->length); // Avoid crash + /* purecov: end */ + return sort_field->original_length; + } + } + return sort_field->pack_sort_string(to, res->lex_cstring(), cs); +} + + +uint +Type_handler_int_result::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + longlong value= item->val_int_result(); + return make_packed_sort_key_longlong(to, item->maybe_null, + item->null_value, item->unsigned_flag, + value, sort_field); +} + + +uint +Type_handler_decimal_result::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf); + if (item->maybe_null) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0), + item->decimals); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; +} + + +uint +Type_handler_real_result::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + double value= item->val_result(); + if (item->maybe_null) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + change_double_for_sort(value, to); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; +} + + +uint +Type_handler_temporal_result::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + MYSQL_TIME buf; + // This is a temporal type. No nanoseconds. Rounding mode is not important. + DBUG_ASSERT(item->cmp_type() == TIME_RESULT); + static const Temporal::Options opt(TIME_INVALID_DATES, TIME_FRAC_NONE); + if (item->get_date_result(current_thd, &buf, opt)) + { + DBUG_ASSERT(item->maybe_null); + DBUG_ASSERT(item->null_value); + return make_packed_sort_key_longlong(to, item->maybe_null, true, + item->unsigned_flag, 0, sort_field); + } + return make_packed_sort_key_longlong(to, item->maybe_null, false, + item->unsigned_flag, pack_time(&buf), + sort_field); +} + + +uint +Type_handler_timestamp_common::make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + THD *thd= current_thd; + uint binlen= my_timestamp_binary_length(item->decimals); + Timestamp_or_zero_datetime_native_null native(thd, item); + if (native.is_null() || native.is_zero_datetime()) + { + // NULL or '0000-00-00 00:00:00' + if (item->maybe_null) + { + *to++=0; + return 0; + } + else + { + bzero(to, binlen); + return binlen; + } + } + else + { + if (item->maybe_null) + *to++= 1; + if (native.length() != binlen) + { + /* + Some items can return native representation with a different + number of fractional digits, e.g.: GREATEST(ts_3, ts_4) can + return a value with 3 fractional digits, although its fractional + precision is 4. Re-pack with a proper precision now. + */ + Timestamp(native).to_native(&native, item->datetime_precision(thd)); + } + DBUG_ASSERT(native.length() == binlen); + memcpy((char *) to, native.ptr(), binlen); + return binlen; + } +} + + +/* + @brief + Reverse the key for DESC clause + @param to buffer where values are written + @param maybe_null nullability of a column + @param sort_field Sort field structure + @details + used for mem-comparable sort keys +*/ + +void reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field) +{ + uint length; + if (sort_field->maybe_null && (to[-1]= !to[-1])) + { + to+= sort_field->length; // don't waste the time reversing all 0's + return; + } + length=sort_field->length; + while (length--) + { + *to = (uchar) (~ *to); + to++; + } +} + + +/* + @brief + Check if packing sort keys is allowed + @param THD thread structure + @retval + TRUE packing allowed + FALSE packing not allowed +*/ +bool SORT_FIELD_ATTR::check_if_packing_possible(THD *thd) const +{ + /* + Packing not allowed when original length is greater than max_sort_length + and we have a complex collation because cutting a prefix is not safe in + such a case + */ + if (original_length > thd->variables.max_sort_length && + cs->state & MY_CS_NON1TO1) + return false; + return true; +} + + +/* + Compare function used for packing sort keys +*/ + +qsort2_cmp get_packed_keys_compare_ptr() +{ + return (qsort2_cmp) compare_packed_sort_keys; +} + + +/* + Compare two varstrings. + + The strings are in this data format: + + [null_byte] [length of string + suffix_bytes] [the string] [suffix_bytes] + + suffix_bytes are used only for binary columns. +*/ + +int SORT_FIELD_ATTR::compare_packed_varstrings(uchar *a, size_t *a_len, + uchar *b, size_t *b_len) +{ + int retval; + size_t a_length, b_length; + if (maybe_null) + { + *a_len= *b_len= 1; // NULL bytes are always stored + if (*a != *b) + { + // Note we don't return a proper value in *{a|b}_len for the non-NULL + // value but that's ok + if (*a == 0) + return -1; + else + return 1; + } + else + { + if (*a == 0) + return 0; + } + a++; + b++; + } + else + *a_len= *b_len= 0; + + a_length= read_keypart_length(a, length_bytes); + b_length= read_keypart_length(b, length_bytes); + + *a_len+= length_bytes + a_length; + *b_len+= length_bytes + b_length; + + retval= cs->strnncollsp(a + length_bytes, + a_length - suffix_length, + b + length_bytes, + b_length - suffix_length); + + if (!retval && suffix_length) + { + DBUG_ASSERT(cs == &my_charset_bin); + // comparing the length stored in suffix bytes for binary strings + a= a + length_bytes + a_length - suffix_length; + b= b + length_bytes + b_length - suffix_length; + retval= memcmp(a, b, suffix_length); + } + + return retval; +} + + +/* + A value comparison function that has a signature that's suitable for + comparing packed values, but actually compares fixed-size values with memcmp. + + This is used for ordering fixed-size columns when the sorting procedure used + packed-value format. +*/ + +int SORT_FIELD_ATTR::compare_packed_fixed_size_vals(uchar *a, size_t *a_len, + uchar *b, size_t *b_len) +{ + if (maybe_null) + { + *a_len=1; + *b_len=1; + if (*a != *b) + { + if (*a == 0) + return -1; + else + return 1; + } + else + { + if (*a == 0) + return 0; + } + a++; + b++; + } + else + *a_len= *b_len= 0; + + *a_len+= length; + *b_len+= length; + return memcmp(a,b, length); +} + + +/* + @brief + Comparison function to compare two packed sort keys + + @param sort_param cmp argument + @param a_ptr packed sort key + @param b_ptr packed sort key + + @retval + >0 key a_ptr greater than b_ptr + =0 key a_ptr equal to b_ptr + <0 key a_ptr less than b_ptr + +*/ + +int compare_packed_sort_keys(void *sort_param, + unsigned char **a_ptr, unsigned char **b_ptr) +{ + int retval= 0; + size_t a_len, b_len; + Sort_param *param= (Sort_param*)sort_param; + Sort_keys *sort_keys= param->sort_keys; + uchar *a= *a_ptr; + uchar *b= *b_ptr; + + a+= Sort_keys::size_of_length_field; + b+= Sort_keys::size_of_length_field; + for (SORT_FIELD *sort_field= sort_keys->begin(); + sort_field != sort_keys->end(); sort_field++) + { + retval= sort_field->is_variable_sized() ? + sort_field->compare_packed_varstrings(a, &a_len, b, &b_len) : + sort_field->compare_packed_fixed_size_vals(a, &a_len, b, &b_len); + + if (retval) + return sort_field->reverse ? -retval : retval; + + a+= a_len; + b+= b_len; + + } + /* + this comparison is done for the case when the sort keys is appended with + the ROW_ID pointer. For such cases we don't have addon fields + so we can make a memcmp check over both the sort keys + */ + if (!param->using_addon_fields()) + retval= memcmp(a, b, param->res_length); + return retval; +} + + +/* + @brief + Store a packed string in the buffer + + @param to buffer + @param str packed string value + @param cs character set + + @details + This function writes to the buffer the packed value of a key_part + of the sort key. + + The values written to the buffer are in this order + - value for null byte + - length of the string + - value of the string + - suffix length (for binary character set) +*/ + +uint +SORT_FIELD_ATTR::pack_sort_string(uchar *to, const LEX_CSTRING &str, + CHARSET_INFO *cs) const +{ + uchar *orig_to= to; + uint32 length, data_length; + DBUG_ASSERT(str.length <= UINT32_MAX); + length= (uint32)str.length; + + if (length + suffix_length <= original_length) + data_length= length; + else + data_length= original_length - suffix_length; + + // length stored in lowendian form + store_key_part_length(data_length + suffix_length, to, length_bytes); + to+= length_bytes; + // copying data length bytes to the buffer + memcpy(to, (uchar*)str.str, data_length); + to+= data_length; + + if (cs == &my_charset_bin && suffix_length) + { + // suffix length stored in bigendian form + store_bigendian(str.length, to, suffix_length); + to+= suffix_length; + } + return static_cast<uint>(to - orig_to); +} + + +/* + @brief + Create a mem-comparable sort key + + @param param sort param structure + @param to buffer where values are written + + @retval + length of the bytes written including the NULL bytes +*/ + +static uint make_sortkey(Sort_param *param, uchar *to) +{ + Field *field; + SORT_FIELD *sort_field; + uchar *orig_to= to; + + for (sort_field=param->local_sortorder.begin() ; + sort_field != param->local_sortorder.end() ; + sort_field++) + { + bool maybe_null=0; + if ((field=sort_field->field)) + { + // Field + field->make_sort_key_part(to, sort_field->length); + if ((maybe_null= field->maybe_null())) + to++; + } + else + { // Item + sort_field->item->type_handler()->make_sort_key_part(to, + sort_field->item, + sort_field, param); + if ((maybe_null= sort_field->item->maybe_null)) + to++; + } + + if (sort_field->reverse) + reverse_key(to, sort_field); + to+= sort_field->length; + } + + DBUG_ASSERT(static_cast<uint>(to - orig_to) <= param->sort_length); + return static_cast<uint>(to - orig_to); +} + + +/* + @brief + create a compact sort key which can be compared with a comparison + function. They are called packed sort keys + + @param param sort param structure + @param to buffer where values are written + + @retval + length of the bytes written including the NULL bytes +*/ + +static uint make_packed_sortkey(Sort_param *param, uchar *to) +{ + Field *field; + SORT_FIELD *sort_field; + uint length; + uchar *orig_to= to; + + to+= Sort_keys::size_of_length_field; + + for (sort_field=param->local_sortorder.begin() ; + sort_field != param->local_sortorder.end() ; + sort_field++) + { + bool maybe_null=0; + if ((field=sort_field->field)) + { + // Field + length= field->make_packed_sort_key_part(to, sort_field); + if ((maybe_null= field->maybe_null())) + to++; + } + else + { // Item + Item *item= sort_field->item; + length= item->type_handler()->make_packed_sort_key_part(to, item, + sort_field, + param); + if ((maybe_null= sort_field->item->maybe_null)) + to++; + } + to+= length; + } + + length= static_cast<int>(to - orig_to); + DBUG_ASSERT(length <= param->sort_length); + Sort_keys::store_sortkey_length(orig_to, length); + return length; +} diff --git a/sql/filesort.h b/sql/filesort.h index 5102ee2326f..9f71da02c96 100644 --- a/sql/filesort.h +++ b/sql/filesort.h @@ -25,9 +25,12 @@ class THD; struct TABLE; class Filesort_tracker; struct SORT_FIELD; +struct SORT_FIELD_ATTR; typedef struct st_order ORDER; class JOIN; class Addon_fields; +class Sort_keys; + /** Sorting related info. @@ -57,6 +60,7 @@ public: bool sort_positions; Filesort_tracker *tracker; + Sort_keys *sort_keys; Filesort(ORDER *order_arg, ha_rows limit_arg, bool sort_positions_arg, SQL_SELECT *select_arg): @@ -66,14 +70,15 @@ public: select(select_arg), own_select(false), using_pq(false), - sort_positions(sort_positions_arg) + sort_positions(sort_positions_arg), + sort_keys(NULL) { DBUG_ASSERT(order); }; ~Filesort() { cleanup(); } /* Prepare ORDER BY list for sorting. */ - uint make_sortorder(THD *thd, JOIN *join, table_map first_table_bit); + Sort_keys* make_sortorder(THD *thd, JOIN *join, table_map first_table_bit); private: void cleanup(); @@ -88,6 +93,7 @@ class SORT_INFO public: SORT_INFO() :addon_fields(NULL), record_pointers(0), + sort_keys(NULL), sorted_result_in_fsbuf(FALSE) { buffpek.str= 0; @@ -121,6 +127,7 @@ public: LEX_STRING buffpek; /* Buffer for buffpek structures */ Addon_fields *addon_fields; /* Addon field descriptors */ uchar *record_pointers; /* If sorted in memory */ + Sort_keys *sort_keys; /* Sort key descriptors*/ /** If the entire result of filesort fits in memory, we skip the merge phase. @@ -201,6 +208,7 @@ public: template<bool Packed_addon_fields> inline void unpack_addon_fields(uchar *buff); + bool using_packed_sortkeys(); friend SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, Filesort_tracker* tracker, JOIN *join, @@ -216,5 +224,8 @@ bool filesort_use_addons(TABLE *table, uint sortlength, uint *m_packable_length); void change_double_for_sort(double nr,uchar *to); +void store_length(uchar *to, uint length, uint pack_length); +void +reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field); #endif /* FILESORT_INCLUDED */ diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc index 95b9dc51cf8..d178740d24b 100644 --- a/sql/filesort_utils.cc +++ b/sql/filesort_utils.cc @@ -20,6 +20,8 @@ #include "table.h" +PSI_memory_key key_memory_Filesort_buffer_sort_keys; + namespace { /** A local helper function. See comments for get_merge_buffers_cost(). @@ -128,7 +130,8 @@ uchar *Filesort_buffer::alloc_sort_buffer(uint num_records, the old values */ my_free(m_rawmem); - if (!(m_rawmem= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC)))) + if (!(m_rawmem= (uchar*) my_malloc(key_memory_Filesort_buffer_sort_keys, + buff_size, MYF(MY_THREAD_SPECIFIC)))) { m_size_in_bytes= 0; DBUG_RETURN(0); @@ -137,7 +140,8 @@ uchar *Filesort_buffer::alloc_sort_buffer(uint num_records, } else { - if (!(m_rawmem= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC)))) + if (!(m_rawmem= (uchar*) my_malloc(key_memory_Filesort_buffer_sort_keys, + buff_size, MYF(MY_THREAD_SPECIFIC)))) { m_size_in_bytes= 0; DBUG_RETURN(0); @@ -175,14 +179,17 @@ void Filesort_buffer::sort_buffer(const Sort_param *param, uint count) reverse_record_pointers(); uchar **buffer= NULL; - if (radixsort_is_appliccable(count, param->sort_length) && - (buffer= (uchar**) my_malloc(count*sizeof(char*), + if (!param->using_packed_sortkeys() && + radixsort_is_appliccable(count, param->sort_length) && + (buffer= (uchar**) my_malloc(PSI_INSTRUMENT_ME, count*sizeof(char*), MYF(MY_THREAD_SPECIFIC)))) { radixsort_for_str_ptr(m_sort_keys, count, param->sort_length, buffer); my_free(buffer); return; } - - my_qsort2(m_sort_keys, count, sizeof(uchar*), get_ptr_compare(size), &size); + + my_qsort2(m_sort_keys, count, sizeof(uchar*), + param->get_compare_function(), + param->get_compare_argument(&size)); } diff --git a/sql/filesort_utils.h b/sql/filesort_utils.h index e8b93940abf..1962f149893 100644 --- a/sql/filesort_utils.h +++ b/sql/filesort_utils.h @@ -279,4 +279,8 @@ private: longlong m_idx; }; +int compare_packed_sort_keys(void *sort_keys, unsigned char **a, + unsigned char **b); +qsort2_cmp get_packed_keys_compare_ptr(); + #endif // FILESORT_UTILS_INCLUDED diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 4919e5b959b..6d7ab7e29c3 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -204,7 +204,7 @@ void Gcalc_dyn_list::format_blk(void* block) Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk() { - void *new_block= my_malloc(m_blk_size, MYF(MY_WME)); + void *new_block= my_malloc(PSI_INSTRUMENT_ME, m_blk_size, MYF(MY_WME)); if (!new_block) return NULL; *m_blk_hook= new_block; diff --git a/sql/gstream.cc b/sql/gstream.cc index b743140ba59..f8e84e70560 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -23,6 +23,7 @@ #include "sql_priv.h" #include "gstream.h" #include "m_string.h" // LEX_STRING +#include "mysqld.h" enum Gis_read_stream::enum_tok_types Gis_read_stream::get_next_toc_type() { @@ -140,6 +141,7 @@ bool Gis_read_stream::check_next_symbol(char symbol) void Gis_read_stream::set_error_msg(const char *msg) { size_t len= strlen(msg); // ok in this context - m_err_msg= (char *) my_realloc(m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR)); + m_err_msg= (char *) my_realloc(key_memory_Gis_read_stream_err_msg, + m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR)); memcpy(m_err_msg, msg, len + 1); } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d36a58aef20..f30ef6a9688 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -102,22 +102,43 @@ static const char *ha_partition_ext[]= ha_par_ext, NullS }; +static PSI_memory_key key_memory_Partition_share; +static PSI_memory_key key_memory_partition_sort_buffer; +static PSI_memory_key key_memory_Partition_admin; + +static PSI_memory_key key_memory_ha_partition_file; +//static PSI_memory_key key_memory_ha_partition_engine_array; +static PSI_memory_key key_memory_ha_partition_part_ids; #ifdef HAVE_PSI_INTERFACE PSI_mutex_key key_partition_auto_inc_mutex; +PSI_file_key key_file_ha_partition_par; static PSI_mutex_info all_partition_mutexes[]= { { &key_partition_auto_inc_mutex, "Partition_share::auto_inc_mutex", 0} }; +static PSI_memory_info all_partitioning_memory[]= +{ { &key_memory_Partition_share, "Partition_share", 0}, + { &key_memory_partition_sort_buffer, "partition_sort_buffer", 0}, + { &key_memory_Partition_admin, "Partition_admin", 0}, + { &key_memory_ha_partition_file, "ha_partition::file", 0}, +// { &key_memory_ha_partition_engine_array, "ha_partition::engine_array", 0}, + { &key_memory_ha_partition_part_ids, "ha_partition::part_ids", 0} }; +static PSI_file_info all_partition_file[]= +{ { &key_file_ha_partition_par, "ha_partition::parfile", 0} }; static void init_partition_psi_keys(void) { const char* category= "partition"; int count; + count= array_elements(all_partitioning_memory); + mysql_memory_register(category, all_partitioning_memory, count); count= array_elements(all_partition_mutexes); mysql_mutex_register(category, all_partition_mutexes, count); + count= array_elements(all_partition_file); + mysql_file_register(category, all_partition_file, count); } #endif /* HAVE_PSI_INTERFACE */ @@ -244,7 +265,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share) void ha_partition::ha_partition_init() { - init_alloc_root(&m_mem_root, "ha_partition", 512, 512, MYF(0)); + init_alloc_root(PSI_INSTRUMENT_ME, &m_mem_root, 512, 512, MYF(0)); init_handler_variables(); } @@ -649,9 +670,9 @@ int ha_partition::create_partitioning_metadata(const char *path, strxmov(name, path, ha_par_ext, NullS); strxmov(old_name, old_path, ha_par_ext, NullS); if ((action_flag == CHF_DELETE_FLAG && - mysql_file_delete(key_file_partition, name, MYF(MY_WME))) || + mysql_file_delete(key_file_ha_partition_par, name, MYF(MY_WME))) || (action_flag == CHF_RENAME_FLAG && - mysql_file_rename(key_file_partition, old_name, name, MYF(MY_WME)))) + mysql_file_rename(key_file_ha_partition_par, old_name, name, MYF(MY_WME)))) { DBUG_RETURN(TRUE); } @@ -1333,7 +1354,7 @@ bool print_admin_msg(THD* thd, uint len, char *msgbuf; bool error= true; - if (!(msgbuf= (char*) my_malloc(len, MYF(0)))) + if (!(msgbuf= (char*) my_malloc(key_memory_Partition_admin, len, MYF(0)))) return true; va_start(args, fmt); msg_length= my_vsnprintf(msgbuf, len, fmt, args); @@ -2749,7 +2770,8 @@ bool ha_partition::create_handler_file(const char *name) /* 4 static words (tot words, checksum, tot partitions, name length) */ tot_len_words= 4 + tot_partition_words + tot_name_words; tot_len_byte= PAR_WORD_SIZE * tot_len_words; - if (!(file_buffer= (uchar *) my_malloc(tot_len_byte, MYF(MY_ZEROFILL)))) + if (!(file_buffer= (uchar *) my_malloc(key_memory_ha_partition_file, + tot_len_byte, MYF(MY_ZEROFILL)))) DBUG_RETURN(TRUE); engine_array= (file_buffer + PAR_ENGINES_OFFSET); name_buffer_ptr= (char*) (engine_array + tot_partition_words * PAR_WORD_SIZE @@ -2804,7 +2826,7 @@ bool ha_partition::create_handler_file(const char *name) to be used at open, delete_table and rename_table */ fn_format(file_name, name, "", ha_par_ext, MY_APPEND_EXT); - if ((file= mysql_file_create(key_file_partition, + if ((file= mysql_file_create(key_file_ha_partition_par, file_name, CREATE_MODE, O_RDWR | O_TRUNC, MYF(MY_WME))) >= 0) { @@ -2829,7 +2851,7 @@ bool ha_partition::create_handler_file(const char *name) } (void) mysql_file_close(file, MYF(0)); if (result) - mysql_file_delete(key_file_partition, file_name, MYF(MY_WME)); + mysql_file_delete(key_file_ha_partition_par, file_name, MYF(MY_WME)); } else result= TRUE; @@ -2993,7 +3015,7 @@ bool ha_partition::read_par_file(const char *name) fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT); /* Following could be done with mysql_file_stat to read in whole file */ - if ((file= mysql_file_open(key_file_partition, + if ((file= mysql_file_open(key_file_ha_partition_par, buff, O_RDONLY | O_SHARE, MYF(0))) < 0) DBUG_RETURN(TRUE); if (mysql_file_read(file, (uchar *) &buff[0], PAR_WORD_SIZE, MYF(MY_NABP))) @@ -3219,7 +3241,7 @@ bool ha_partition::insert_partition_name_in_hash(const char *name, uint part_id, Since we use my_multi_malloc, then my_free(part_def) will also free part_name, as a part of my_hash_free. */ - if (!my_multi_malloc(MY_WME, + if (!my_multi_malloc(key_memory_Partition_share, MY_WME, &part_def, sizeof(PART_NAME_DEF), &part_name, part_name_length + 1, NULL)) @@ -3267,10 +3289,10 @@ bool ha_partition::populate_partition_name_hash() DBUG_RETURN(false); } tot_names= m_is_sub_partitioned ? m_tot_parts + num_parts : num_parts; - if (my_hash_init(&part_share->partition_name_hash, - system_charset_info, tot_names, 0, 0, - (my_hash_get_key) get_part_name, - my_free, HASH_UNIQUE)) + if (my_hash_init(key_memory_Partition_share, + &part_share->partition_name_hash, system_charset_info, + tot_names, 0, 0, (my_hash_get_key) get_part_name, my_free, + HASH_UNIQUE)) { unlock_shared_ha_data(); DBUG_RETURN(TRUE); @@ -3506,7 +3528,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) if (!m_part_ids_sorted_by_num_of_records) { if (!(m_part_ids_sorted_by_num_of_records= - (uint32*) my_malloc(m_tot_parts * sizeof(uint32), MYF(MY_WME)))) + (uint32*) my_malloc(key_memory_ha_partition_part_ids, + m_tot_parts * sizeof(uint32), MYF(MY_WME)))) DBUG_RETURN(error); uint32 i; /* Initialize it with all partition ids. */ @@ -3524,7 +3547,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) /* Allocate memory used with MMR */ if (!(m_range_info= (void **) - my_multi_malloc(MYF(MY_WME), + my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &m_range_info, sizeof(range_id_t) * m_tot_parts, &m_stock_range_seq, sizeof(uint) * m_tot_parts, &m_mrr_buffer, sizeof(HANDLER_BUFFER) * m_tot_parts, @@ -3535,8 +3558,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) &m_part_mrr_range_current, sizeof(PARTITION_PART_KEY_MULTI_RANGE *) * m_tot_parts, &m_partition_part_key_multi_range_hld, - sizeof(PARTITION_PART_KEY_MULTI_RANGE_HLD) * - m_tot_parts, + sizeof(PARTITION_PART_KEY_MULTI_RANGE_HLD) * m_tot_parts, NullS))) goto err_alloc; @@ -5315,7 +5337,8 @@ bool ha_partition::init_record_priority_queue() /* Allocate a key for temporary use when setting up the scan. */ alloc_len+= table_share->max_key_length; - if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME)))) + if (!(m_ordered_rec_buffer= (uchar*)my_malloc(key_memory_partition_sort_buffer, + alloc_len, MYF(MY_WME)))) DBUG_RETURN(true); /* @@ -6066,9 +6089,8 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, if (!m_mrr_range_first) { if (!(m_mrr_range_first= (PARTITION_KEY_MULTI_RANGE *) - my_multi_malloc(MYF(MY_WME), - &m_mrr_range_current, - sizeof(PARTITION_KEY_MULTI_RANGE), + my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), + &m_mrr_range_current, sizeof(PARTITION_KEY_MULTI_RANGE), NullS))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -6085,9 +6107,8 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, if (!m_part_mrr_range_first[i]) { if (!(m_part_mrr_range_first[i]= (PARTITION_PART_KEY_MULTI_RANGE *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &m_part_mrr_range_current[i], - sizeof(PARTITION_PART_KEY_MULTI_RANGE), + my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL), + &m_part_mrr_range_current[i], sizeof(PARTITION_PART_KEY_MULTI_RANGE), NullS))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); } @@ -6123,7 +6144,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, if (m_mrr_range_current->key[0]) my_free(m_mrr_range_current->key[0]); if (!(m_mrr_range_current->key[0]= - (uchar *) my_malloc(length, MYF(MY_WME)))) + (uchar *) my_malloc(PSI_INSTRUMENT_ME, length, MYF(MY_WME)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); m_mrr_range_current->length[0]= length; } @@ -6147,7 +6168,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, if (m_mrr_range_current->key[1]) my_free(m_mrr_range_current->key[1]); if (!(m_mrr_range_current->key[1]= - (uchar *) my_malloc(length, MYF(MY_WME)))) + (uchar *) my_malloc(PSI_INSTRUMENT_ME, length, MYF(MY_WME)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); m_mrr_range_current->length[1]= length; } @@ -6181,7 +6202,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, { PARTITION_PART_KEY_MULTI_RANGE *tmp_part_mrr_range; if (!(tmp_part_mrr_range= (PARTITION_PART_KEY_MULTI_RANGE *) - my_malloc(sizeof(PARTITION_PART_KEY_MULTI_RANGE), + my_malloc(PSI_INSTRUMENT_ME, sizeof(PARTITION_PART_KEY_MULTI_RANGE), MYF(MY_WME | MY_ZEROFILL)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -6201,7 +6222,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq, /* Add end of range sentinel */ PARTITION_KEY_MULTI_RANGE *tmp_mrr_range; if (!(tmp_mrr_range= (PARTITION_KEY_MULTI_RANGE *) - my_malloc(sizeof(PARTITION_KEY_MULTI_RANGE), MYF(MY_WME)))) + my_malloc(PSI_INSTRUMENT_ME, sizeof(PARTITION_KEY_MULTI_RANGE), MYF(MY_WME)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); tmp_mrr_range->id= m_mrr_range_current->id + 1; @@ -6472,7 +6493,7 @@ int ha_partition::multi_range_read_init(RANGE_SEQ_IF *seq, if (m_mrr_full_buffer) my_free(m_mrr_full_buffer); if (!(m_mrr_full_buffer= - (uchar *) my_malloc(m_mrr_new_full_buffer_size, MYF(MY_WME)))) + (uchar *) my_malloc(PSI_INSTRUMENT_ME, m_mrr_new_full_buffer_size, MYF(MY_WME)))) { m_mrr_full_buffer_size= 0; error= HA_ERR_OUT_OF_MEM; @@ -6870,11 +6891,9 @@ FT_INFO *ha_partition::ft_init_ext(uint flags, uint inx, String *key) { FT_INFO **tmp_ft_info; if (!(ft_target= (st_partition_ft_info *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &ft_target, - sizeof(st_partition_ft_info), - &tmp_ft_info, - sizeof(FT_INFO *) * m_tot_parts, + my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL), + &ft_target, sizeof(st_partition_ft_info), + &tmp_ft_info, sizeof(FT_INFO *) * m_tot_parts, NullS))) { my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc index 5db10c2fada..44ad8ddc865 100644 --- a/sql/handle_connections_win.cc +++ b/sql/handle_connections_win.cc @@ -360,7 +360,7 @@ struct Pipe_Listener : public Listener { sql_perror("Create named pipe failed"); sql_print_error("Aborting"); - exit(1); + unireg_abort(1); } first_instance= false; return pipe_handle; diff --git a/sql/handler.cc b/sql/handler.cc index 7d61252eea6..4dd915d8b91 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -30,7 +30,6 @@ #include "key.h" // key_copy, key_unpack, key_cmp_if_same, key_cmp #include "sql_table.h" // build_table_filename #include "sql_parse.h" // check_stack_overrun -#include "sql_acl.h" // SUPER_ACL #include "sql_base.h" // TDC_element #include "discover.h" // extension_based_table_discovery, etc #include "log_event.h" // *_rows_log_event @@ -40,6 +39,8 @@ #include "myisam.h" #include "probes_mysql.h" #include <mysql/psi/mysql_table.h> +#include <pfs_transaction_provider.h> +#include <mysql/psi/mysql_transaction.h> #include "debug_sync.h" // DEBUG_SYNC #include "sql_audit.h" #include "ha_sequence.h" @@ -62,6 +63,39 @@ #include "wsrep_trans_observer.h" /* wsrep transaction hooks */ #endif /* WITH_WSREP */ +/** + @def MYSQL_TABLE_LOCK_WAIT + Instrumentation helper for table io_waits. + @param OP the table operation to be performed + @param FLAGS per table operation flags. + @param PAYLOAD the code to instrument. + @sa MYSQL_END_TABLE_WAIT. +*/ +#ifdef HAVE_PSI_TABLE_INTERFACE + #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \ + { \ + if (m_psi != NULL) \ + { \ + PSI_table_locker *locker; \ + PSI_table_locker_state state; \ + locker= PSI_TABLE_CALL(start_table_lock_wait) \ + (& state, m_psi, OP, FLAGS, \ + __FILE__, __LINE__); \ + PAYLOAD \ + if (locker != NULL) \ + PSI_TABLE_CALL(end_table_lock_wait)(locker); \ + } \ + else \ + { \ + PAYLOAD \ + } \ + } +#else + #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \ + PAYLOAD +#endif + + /* While we have legacy_db_type, we have this array to check for dups and to find handlerton from legacy_db_type. @@ -361,7 +395,8 @@ int ha_init_errors(void) /* Allocate a pointer array for the error message strings. */ /* Zerofill it to avoid uninitialized gaps. */ - if (! (handler_errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*), + if (! (handler_errmsgs= (const char**) my_malloc(key_memory_handler_errmsgs, + HA_ERR_ERRORS * sizeof(char*), MYF(MY_WME | MY_ZEROFILL)))) return 1; @@ -531,7 +566,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin) DBUG_ENTER("ha_initialize_handlerton"); DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str)); - hton= (handlerton *)my_malloc(sizeof(handlerton), + hton= (handlerton *)my_malloc(key_memory_handlerton, sizeof(handlerton), MYF(MY_WME | MY_ZEROFILL)); if (hton == NULL) { @@ -1200,7 +1235,7 @@ void ha_pre_shutdown() times per transaction. */ -void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) +void trans_register_ha(THD *thd, bool all, handlerton *ht_arg, ulonglong trxid) { THD_TRANS *trans; Ha_trx_info *ha_info; @@ -1231,6 +1266,25 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) if (thd->transaction.implicit_xid.is_null()) thd->transaction.implicit_xid.set(thd->query_id); +/* + Register transaction start in performance schema if not done already. + By doing this, we handle cases when the transaction is started implicitly in + autocommit=0 mode, and cases when we are in normal autocommit=1 mode and the + executed statement is a single-statement transaction. + + Explicitly started transactions are handled in trans_begin(). + + Do not register transactions in which binary log is the only participating + transactional storage engine. +*/ + if (thd->m_transaction_psi == NULL && ht_arg->db_type != DB_TYPE_BINLOG) + { + thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state, + thd->get_xid(), trxid, thd->tx_isolation, thd->tx_read_only, + !thd->in_multi_stmt_transaction_mode()); + DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid"); + //gtid_set_performance_schema_values(thd); + } DBUG_VOID_RETURN; } @@ -1456,12 +1510,14 @@ int ha_commit_trans(THD *thd, bool all) Free resources and perform other cleanup even for 'empty' transactions. */ if (is_real_trans) + { thd->transaction.cleanup(); + MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); + thd->m_transaction_psi= NULL; + } #ifdef WITH_WSREP if (wsrep_is_active(thd) && is_real_trans && !error) - { wsrep_commit_empty(thd, all); - } #endif /* WITH_WSREP */ DBUG_RETURN(0); } @@ -1490,7 +1546,8 @@ int ha_commit_trans(THD *thd, bool all) We allow the owner of FTWRL to COMMIT; we assume that it knows what it does. */ - mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, + MDL_EXPLICIT); if (!WSREP(thd) && thd->mdl_context.acquire_lock(&mdl_request, @@ -1505,7 +1562,7 @@ int ha_commit_trans(THD *thd, bool all) if (rw_trans && opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && + !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && !thd->slave_thread) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); @@ -1651,12 +1708,15 @@ int ha_commit_trans(THD *thd, bool all) #endif /* WITH_WSREP */ DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE();); if (tc_log->unlog(cookie, xid)) - { error= 2; /* Error during commit */ - goto end; - } done: + if (is_real_trans) + { + MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); + thd->m_transaction_psi= NULL; + } + DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE();); mysql_mutex_assert_not_owner(&LOCK_prepare_ordered); @@ -1694,6 +1754,8 @@ err: ha_rollback_trans(thd, all); else { + MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi); + thd->m_transaction_psi= NULL; WSREP_DEBUG("rollback skipped %p %d",thd->rgi_slave, thd->rgi_slave->is_parallel_exec); } @@ -1913,6 +1975,13 @@ int ha_rollback_trans(THD *thd, bool all) } (void) wsrep_after_rollback(thd, all); #endif /* WITH_WSREP */ + + if (all || !thd->in_active_multi_stmt_transaction()) + { + MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi); + thd->m_transaction_psi= NULL; + } + /* Always cleanup. Even if nht==0. There may be savepoints. */ if (is_real_trans) { @@ -2218,7 +2287,7 @@ int ha_recover(HASH *commit_list) info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2) { DBUG_EXECUTE_IF("min_xa_len", info.len = 16;); - info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0)); + info.list=(XID *)my_malloc(key_memory_XID, info.len*sizeof(XID), MYF(0)); } if (!info.list) { @@ -2360,6 +2429,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) ha_info->reset(); /* keep it conveniently zero-filled */ } trans->ha_list= sv->ha_list; + + if (thd->m_transaction_psi != NULL) + MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(thd->m_transaction_psi, 1); + DBUG_RETURN(error); } @@ -2411,6 +2484,9 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) */ sv->ha_list= trans->ha_list; + if (!error && thd->m_transaction_psi != NULL) + MYSQL_INC_TRANSACTION_SAVEPOINTS(thd->m_transaction_psi, 1); + DBUG_RETURN(error); } @@ -2435,6 +2511,10 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv) error=1; } } + + if (thd->m_transaction_psi != NULL) + MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(thd->m_transaction_psi, 1); + DBUG_RETURN(error); } @@ -2702,6 +2782,30 @@ void handler::rebind_psi() } +void handler::start_psi_batch_mode() +{ +#ifdef HAVE_PSI_TABLE_INTERFACE + DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_NONE); + DBUG_ASSERT(m_psi_locker == NULL); + m_psi_batch_mode= PSI_BATCH_MODE_STARTING; + m_psi_numrows= 0; +#endif +} + +void handler::end_psi_batch_mode() +{ +#ifdef HAVE_PSI_TABLE_INTERFACE + DBUG_ASSERT(m_psi_batch_mode != PSI_BATCH_MODE_NONE); + if (m_psi_locker != NULL) + { + DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_STARTED); + PSI_TABLE_CALL(end_table_io_wait)(m_psi_locker, m_psi_numrows); + m_psi_locker= NULL; + } + m_psi_batch_mode= PSI_BATCH_MODE_NONE; +#endif +} + PSI_table_share *handler::ha_table_share_psi() const { return table_share->m_psi; @@ -2791,8 +2895,10 @@ int handler::ha_close(void) */ if (table->in_use) status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read); - PSI_CALL_close_table(m_psi); + PSI_CALL_close_table(table_share, m_psi); m_psi= NULL; /* instrumentation handle, invalid after close_table() */ + DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_NONE); + DBUG_ASSERT(m_psi_locker == NULL); /* Detach from ANALYZE tracker */ tracker= NULL; @@ -2813,7 +2919,7 @@ int handler::ha_rnd_next(uchar *buf) do { - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, MAX_KEY, result, { result= rnd_next(buf); }) if (result != HA_ERR_RECORD_DELETED) break; @@ -2845,7 +2951,7 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos) m_lock_type != F_UNLCK); DBUG_ASSERT(inited == RND); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, MAX_KEY, result, { result= rnd_pos(buf, pos); }) increment_statistics(&SSV::ha_read_rnd_count); if (result == HA_ERR_RECORD_DELETED) @@ -2870,7 +2976,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key, m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_read_map(buf, key, keypart_map, find_flag); }) increment_statistics(&SSV::ha_read_key_count); if (!result) @@ -2898,7 +3004,7 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key, DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); DBUG_ASSERT(end_range == NULL); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, index, result, { result= index_read_idx_map(buf, index, key, keypart_map, find_flag); }) increment_statistics(&SSV::ha_read_key_count); if (!result) @@ -2920,7 +3026,7 @@ int handler::ha_index_next(uchar * buf) m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_next(buf); }) increment_statistics(&SSV::ha_read_next_count); if (!result) @@ -2941,7 +3047,7 @@ int handler::ha_index_prev(uchar * buf) m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_prev(buf); }) increment_statistics(&SSV::ha_read_prev_count); if (!result) @@ -2961,7 +3067,7 @@ int handler::ha_index_first(uchar * buf) m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_first(buf); }) increment_statistics(&SSV::ha_read_first_count); if (!result) @@ -2981,7 +3087,7 @@ int handler::ha_index_last(uchar * buf) m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_last(buf); }) increment_statistics(&SSV::ha_read_last_count); if (!result) @@ -3001,7 +3107,7 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result, { result= index_next_same(buf, key, keylen); }) increment_statistics(&SSV::ha_read_next_count); if (!result) @@ -4585,7 +4691,8 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table, ALTER_DROP_CHECK_CONSTRAINT | ALTER_PARTITIONED | ALTER_VIRTUAL_GCOL_EXPR | - ALTER_RENAME; + ALTER_RENAME | + ALTER_RENAME_INDEX; /* Is there at least one operation that requires copy algorithm? */ if (ha_alter_info->handler_flags & ~inplace_offline_operations) @@ -4942,7 +5049,7 @@ void handler::update_global_table_stats() table->s->table_cache_key.length))) { if (!(table_stats = ((TABLE_STATS*) - my_malloc(sizeof(TABLE_STATS), + my_malloc(PSI_INSTRUMENT_ME, sizeof(TABLE_STATS), MYF(MY_WME | MY_ZEROFILL))))) { /* Out of memory error already given */ @@ -5007,7 +5114,7 @@ void handler::update_global_index_stats() key_length))) { if (!(index_stats = ((INDEX_STATS*) - my_malloc(sizeof(INDEX_STATS), + my_malloc(PSI_INSTRUMENT_ME, sizeof(INDEX_STATS), MYF(MY_WME | MY_ZEROFILL))))) goto end; // Error is already given @@ -6389,7 +6496,7 @@ int handler::ha_external_lock(THD *thd, int lock_type) We cache the table flags if the locking succeeded. Otherwise, we keep them as they were when they were fetched in ha_open(). */ - MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type, + MYSQL_TABLE_LOCK_WAIT(PSI_TABLE_EXTERNAL_LOCK, lock_type, { error= external_lock(thd, lock_type); }) DBUG_EXECUTE_IF("external_lock_failure", error= HA_ERR_GENERIC;); @@ -6646,15 +6753,15 @@ int handler::ha_write_row(const uchar *buf) mark_trx_read_write(); increment_statistics(&SSV::ha_write_count); - if (table->s->long_unique_table) + if (table->s->long_unique_table && this == table->file) { - if (this->inited == RND) + if (inited == RND) table->clone_handler_for_update(); handler *h= table->update_handler ? table->update_handler : table->file; if ((error= check_duplicate_long_entries(table, h, buf))) DBUG_RETURN(error); } - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) MYSQL_INSERT_ROW_DONE(error); @@ -6699,7 +6806,7 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) return error; } - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, error, { error= update_row(old_data, new_data);}) MYSQL_UPDATE_ROW_DONE(error); @@ -6762,7 +6869,7 @@ int handler::ha_delete_row(const uchar *buf) mark_trx_read_write(); increment_statistics(&SSV::ha_delete_count); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, active_index, error, { error= delete_row(buf);}) MYSQL_DELETE_ROW_DONE(error); if (likely(!error)) @@ -7222,7 +7329,7 @@ int del_global_table_stat(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *ta cache_key_length= db->length + 1 + table->length + 1; - if(!(cache_key= (uchar *)my_malloc(cache_key_length, + if(!(cache_key= (uchar *)my_malloc(PSI_INSTRUMENT_ME, cache_key_length, MYF(MY_WME | MY_ZEROFILL)))) { /* Out of memory error already given */ diff --git a/sql/handler.h b/sql/handler.h index 0a561ec8b3f..f17c303571f 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3115,8 +3115,59 @@ public: */ PSI_table *m_psi; +private: + /** Internal state of the batch instrumentation. */ + enum batch_mode_t + { + /** Batch mode not used. */ + PSI_BATCH_MODE_NONE, + /** Batch mode used, before first table io. */ + PSI_BATCH_MODE_STARTING, + /** Batch mode used, after first table io. */ + PSI_BATCH_MODE_STARTED + }; + /** + Batch mode state. + @sa start_psi_batch_mode. + @sa end_psi_batch_mode. + */ + batch_mode_t m_psi_batch_mode; + /** + The number of rows in the batch. + @sa start_psi_batch_mode. + @sa end_psi_batch_mode. + */ + ulonglong m_psi_numrows; + /** + The current event in a batch. + @sa start_psi_batch_mode. + @sa end_psi_batch_mode. + */ + PSI_table_locker *m_psi_locker; + /** + Storage for the event in a batch. + @sa start_psi_batch_mode. + @sa end_psi_batch_mode. + */ + PSI_table_locker_state m_psi_locker_state; + +public: virtual void unbind_psi(); virtual void rebind_psi(); + /** + Put the handler in 'batch' mode when collecting + table io instrumented events. + When operating in batch mode: + - a single start event is generated in the performance schema. + - all table io performed between @c start_psi_batch_mode + and @c end_psi_batch_mode is not instrumented: + the number of rows affected is counted instead in @c m_psi_numrows. + - a single end event is generated in the performance schema + when the batch mode ends with @c end_psi_batch_mode. + */ + void start_psi_batch_mode(); + /** End a batch started with @c start_psi_batch_mode. */ + void end_psi_batch_mode(); bool set_top_table_fields; struct TABLE *top_table; @@ -3163,7 +3214,11 @@ public: pushed_rowid_filter(NULL), rowid_filter_is_active(0), auto_inc_intervals_count(0), - m_psi(NULL), set_top_table_fields(FALSE), top_table(0), + m_psi(NULL), + m_psi_batch_mode(PSI_BATCH_MODE_NONE), + m_psi_numrows(0), + m_psi_locker(NULL), + set_top_table_fields(FALSE), top_table(0), top_table_field(0), top_table_fields(0), m_lock_type(F_UNLCK), ha_share(NULL), m_prev_insert_id(0) { @@ -4036,11 +4091,10 @@ public: virtual my_bool register_query_cache_table(THD *thd, const char *table_key, uint key_length, - qc_engine_callback - *engine_callback, + qc_engine_callback *callback, ulonglong *engine_data) { - *engine_callback= 0; + *callback= 0; return TRUE; } @@ -5007,7 +5061,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); #endif /* these are called by storage engines */ -void trans_register_ha(THD *thd, bool all, handlerton *ht); +void trans_register_ha(THD *thd, bool all, handlerton *ht, + ulonglong trxid); /* Storage engine has to assume the transaction will end up with 2pc if @@ -5032,13 +5087,82 @@ int binlog_log_row(TABLE* table, const uchar *after_record, Log_func *log_func); -#define TABLE_IO_WAIT(TRACKER, PSI, OP, INDEX, FLAGS, PAYLOAD) \ +/** + @def MYSQL_TABLE_IO_WAIT + Instrumentation helper for table io_waits. + Note that this helper is intended to be used from + within the handler class only, as it uses members + from @c handler + Performance schema events are instrumented as follows: + - in non batch mode, one event is generated per call + - in batch mode, the number of rows affected is saved + in @c m_psi_numrows, so that @c end_psi_batch_mode() + generates a single event for the batch. + @param OP the table operation to be performed + @param INDEX the table index used if any, or MAX_KEY. + @param PAYLOAD instrumented code to execute + @sa handler::end_psi_batch_mode. +*/ +#ifdef HAVE_PSI_TABLE_INTERFACE + #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \ + { \ + if (m_psi != NULL) \ + { \ + switch (m_psi_batch_mode) \ + { \ + case PSI_BATCH_MODE_NONE: \ + { \ + PSI_table_locker *sub_locker= NULL; \ + PSI_table_locker_state reentrant_safe_state; \ + sub_locker= PSI_TABLE_CALL(start_table_io_wait) \ + (& reentrant_safe_state, m_psi, OP, INDEX, \ + __FILE__, __LINE__); \ + PAYLOAD \ + if (sub_locker != NULL) \ + PSI_TABLE_CALL(end_table_io_wait) \ + (sub_locker, 1); \ + break; \ + } \ + case PSI_BATCH_MODE_STARTING: \ + { \ + m_psi_locker= PSI_TABLE_CALL(start_table_io_wait) \ + (& m_psi_locker_state, m_psi, OP, INDEX, \ + __FILE__, __LINE__); \ + PAYLOAD \ + if (!RESULT) \ + m_psi_numrows++; \ + m_psi_batch_mode= PSI_BATCH_MODE_STARTED; \ + break; \ + } \ + case PSI_BATCH_MODE_STARTED: \ + default: \ + { \ + DBUG_ASSERT(m_psi_batch_mode \ + == PSI_BATCH_MODE_STARTED); \ + PAYLOAD \ + if (!RESULT) \ + m_psi_numrows++; \ + break; \ + } \ + } \ + } \ + else \ + { \ + PAYLOAD \ + } \ + } +#else + #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \ + PAYLOAD +#endif + +#define TABLE_IO_WAIT(TRACKER, OP, INDEX, RESULT, PAYLOAD) \ { \ Exec_time_tracker *this_tracker; \ if (unlikely((this_tracker= tracker))) \ tracker->start_tracking(table->in_use); \ \ - MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD); \ + MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD); \ \ if (unlikely(this_tracker)) \ tracker->stop_tracking(table->in_use); \ diff --git a/sql/hash_filo.h b/sql/hash_filo.h index d815c428ac6..ac84e5ccb7b 100644 --- a/sql/hash_filo.h +++ b/sql/hash_filo.h @@ -48,6 +48,7 @@ private: class hash_filo { private: + PSI_memory_key m_psi_key; const uint key_offset, key_length; const my_hash_get_key get_key; /** Size of this hash table. */ @@ -61,15 +62,13 @@ public: mysql_mutex_t lock; HASH cache; - hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg, - my_hash_get_key get_key_arg, my_hash_free_key free_element_arg, - CHARSET_INFO *hash_charset_arg) - :key_offset(key_offset_arg), key_length(key_length_arg), - get_key(get_key_arg), m_size(size_arg), - free_element(free_element_arg),init(0), - hash_charset(hash_charset_arg), - first_link(NULL), - last_link(NULL) + hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg, + uint key_length_arg, my_hash_get_key get_key_arg, + my_hash_free_key free_element_arg, CHARSET_INFO *hash_charset_arg) + : m_psi_key(psi_key), key_offset(key_offset_arg), + key_length(key_length_arg), get_key(get_key_arg), m_size(size_arg), + free_element(free_element_arg),init(0), hash_charset(hash_charset_arg), + first_link(NULL), last_link(NULL) { bzero((char*) &cache,sizeof(cache)); } @@ -95,8 +94,8 @@ public: first_link= NULL; last_link= NULL; (void) my_hash_free(&cache); - (void) my_hash_init(&cache,hash_charset,m_size,key_offset, - key_length, get_key, free_element,0); + (void) my_hash_init(m_psi_key, &cache,hash_charset,m_size,key_offset, + key_length, get_key, free_element, 0); if (!locked) mysql_mutex_unlock(&lock); } @@ -202,10 +201,10 @@ public: template <class T> class Hash_filo: public hash_filo { public: - Hash_filo(uint size_arg, uint key_offset_arg, uint key_length_arg, - my_hash_get_key get_key_arg, my_hash_free_key free_element_arg, - CHARSET_INFO *hash_charset_arg) : - hash_filo(size_arg, key_offset_arg, key_length_arg, + Hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg, uint + key_length_arg, my_hash_get_key get_key_arg, my_hash_free_key + free_element_arg, CHARSET_INFO *hash_charset_arg) : + hash_filo(psi_key, size_arg, key_offset_arg, key_length_arg, get_key_arg, free_element_arg, hash_charset_arg) {} T* first() { return (T*)hash_filo::first(); } T* last() { return (T*)hash_filo::last(); } diff --git a/sql/hostname.cc b/sql/hostname.cc index 968914fd56e..edf31c11081 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -150,10 +150,9 @@ bool hostname_cache_init() Host_entry tmp; uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp); - if (!(hostname_cache= new Hash_filo<Host_entry>(host_cache_size, - key_offset, HOST_ENTRY_KEY_SIZE, - NULL, (my_hash_free_key) free, - &my_charset_bin))) + if (!(hostname_cache= new Hash_filo<Host_entry>(key_memory_host_cache_hostname, + host_cache_size, key_offset, HOST_ENTRY_KEY_SIZE, + NULL, (my_hash_free_key) free, &my_charset_bin))) return 1; hostname_cache->clear(); @@ -476,7 +475,8 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage, if (entry->m_host_validated) { if (entry->m_hostname_length) - *hostname= my_strdup(entry->m_hostname, MYF(0)); + *hostname= my_strdup(key_memory_host_cache_hostname, + entry->m_hostname, MYF(0)); DBUG_PRINT("info",("IP (%s) has been found in the cache. " "Hostname: '%s'", @@ -926,7 +926,8 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage, { /* Copy host name string to be stored in the cache. */ - *hostname= my_strdup(hostname_buffer, MYF(0)); + *hostname= my_strdup(key_memory_host_cache_hostname, + hostname_buffer, MYF(0)); if (!*hostname) { diff --git a/sql/item.cc b/sql/item.cc index 6b585325439..89e23173b0e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -403,7 +403,7 @@ int Item::save_str_value_in_field(Field *field, String *result) Item::Item(THD *thd): is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0), - is_autogenerated_name(TRUE) + common_flags(IS_AUTO_GENERATED_NAME) { DBUG_ASSERT(thd); marker= 0; @@ -463,7 +463,7 @@ Item::Item(THD *thd, Item *item): with_param(item->with_param), with_window_func(item->with_window_func), with_field(item->with_field), - is_autogenerated_name(item->is_autogenerated_name) + common_flags(item->common_flags) { next= thd->free_list; // Put in free list thd->free_list= this; @@ -1117,7 +1117,7 @@ void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs) str++; } } - if (str != str_start && !is_autogenerated_name) + if (str != str_start && !is_autogenerated_name()) { char buff[SAFE_NAME_LEN]; @@ -2771,7 +2771,8 @@ Item_sp::execute_impl(THD *thd, Item **args, uint arg_count) (m_sp->agg_type() == NOT_AGGREGATE && !func_ctx)); if (!func_ctx) { - init_sql_alloc(&sp_mem_root, "Item_sp", MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_sp_head_call_root, &sp_mem_root, + MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); *sp_query_arena= Query_arena(&sp_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP); } @@ -5099,7 +5100,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) /* SELECT list element with explicit alias */ if ((*(cur_group->item))->name.str && !table_name.str && - !(*(cur_group->item))->is_autogenerated_name && + !(*(cur_group->item))->is_autogenerated_name() && !lex_string_cmp(system_charset_info, &(*(cur_group->item))->name, &field_name)) { @@ -6197,6 +6198,9 @@ void Item::init_make_send_field(Send_field *tmp_field, tmp_field->decimals=decimals; if (unsigned_flag) tmp_field->flags |= UNSIGNED_FLAG; + static_cast<Send_field_extended_metadata>(*tmp_field)= + Send_field_extended_metadata(); + h->Item_append_extended_type_info(tmp_field, this); } void Item::make_send_field(THD *thd, Send_field *tmp_field) diff --git a/sql/item.h b/sql/item.h index 6a9d401b101..5eab1d049f0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -624,6 +624,13 @@ class st_select_lex_unit; class Item_func_not; class Item_splocal; +/* Item::common_flags */ +/* Indicates that name of this Item autogenerated or set by user */ +#define IS_AUTO_GENERATED_NAME 1 +/* Indicates that this item is in CYCLE clause of WITH */ +#define IS_IN_WITH_CYCLE 2 + + /** String_copier that sends Item specific warnings. */ @@ -931,8 +938,9 @@ public: True if any item except Item_sum contains a field. Set during parsing. */ bool with_field; - bool is_autogenerated_name; /* indicate was name of this Item - autogenerated or set by user */ + uint8 common_flags; + bool is_autogenerated_name() + { return (common_flags & IS_AUTO_GENERATED_NAME); } // alloc & destruct is done as start of select on THD::mem_root Item(THD *thd); /* @@ -1815,6 +1823,15 @@ public: virtual bool need_parentheses_in_default() { return false; } virtual void save_in_result_field(bool no_conversions) {} /* + Data type format implied by the CHECK CONSTRAINT, + to be sent to the client in the result set metadata. + */ + virtual bool set_format_by_check_constraint(Send_field_extended_metadata *) + const + { + return false; + } + /* set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} @@ -7028,6 +7045,7 @@ public: name= item->name; Type_std_attributes::set(*attr); maybe_null= maybe_null_arg; + common_flags= item->common_flags; } const Type_handler *type_handler() const diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6df2b5dbd3a..7fe16848082 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6481,6 +6481,21 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */ } +bool +Item_cond_and::set_format_by_check_constraint( + Send_field_extended_metadata *to) const +{ + List_iterator_fast<Item> li(const_cast<List<Item>&>(list)); + Item *item; + while ((item= li++)) + { + if (item->set_format_by_check_constraint(to)) + return true; + } + return false; +} + + Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ /* NOT a AND NOT b AND ... */ { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9b20fa50214..8d5cfb359ec 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -3349,6 +3349,7 @@ public: COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref); + bool set_format_by_check_constraint(Send_field_extended_metadata *to) const; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables); SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr); diff --git a/sql/item_create.cc b/sql/item_create.cc index 486f4fc591e..edf44fc3cd3 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1765,6 +1765,15 @@ protected: }; +class Create_func_release_all_locks : public Create_func_arg0 +{ +public: + virtual Item *create_builder(THD *thd); + + static Create_func_release_all_locks s_singleton; +}; + + class Create_func_release_lock : public Create_func_arg1 { public: @@ -2378,7 +2387,7 @@ static bool has_named_parameters(List<Item> *params) List_iterator<Item> it(*params); while ((param= it++)) { - if (! param->is_autogenerated_name) + if (! param->is_autogenerated_name()) return true; } } @@ -2624,7 +2633,7 @@ Create_func_arg1::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list Item *param_1= item_list->pop(); - if (unlikely(! param_1->is_autogenerated_name)) + if (unlikely(! param_1->is_autogenerated_name())) { my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str); return NULL; @@ -2651,8 +2660,8 @@ Create_func_arg2::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list Item *param_1= item_list->pop(); Item *param_2= item_list->pop(); - if (unlikely(!param_1->is_autogenerated_name || - !param_2->is_autogenerated_name)) + if (unlikely(!param_1->is_autogenerated_name() || + !param_2->is_autogenerated_name())) { my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str); return NULL; @@ -2680,9 +2689,9 @@ Create_func_arg3::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list Item *param_2= item_list->pop(); Item *param_3= item_list->pop(); - if (unlikely(!param_1->is_autogenerated_name || - !param_2->is_autogenerated_name || - !param_3->is_autogenerated_name)) + if (unlikely(!param_1->is_autogenerated_name() || + !param_2->is_autogenerated_name() || + !param_3->is_autogenerated_name())) { my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str); return NULL; @@ -4762,6 +4771,17 @@ Create_func_rand::create_native(THD *thd, LEX_CSTRING *name, } +Create_func_release_all_locks Create_func_release_all_locks::s_singleton; + +Item* +Create_func_release_all_locks::create_builder(THD *thd) +{ + thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + return new (thd->mem_root) Item_func_release_all_locks(thd); +} + + Create_func_release_lock Create_func_release_lock::s_singleton; Item* @@ -5525,6 +5545,8 @@ static Native_func_registry func_array[] = { { STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)}, { { STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, { { STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, + { { STRING_WITH_LEN("RELEASE_ALL_LOCKS") }, + BUILDER(Create_func_release_all_locks)}, { { STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)}, { { STRING_WITH_LEN("REPLACE_ORACLE") }, BUILDER(Create_func_replace_oracle)}, @@ -5595,14 +5617,9 @@ int item_create_init() #ifdef HAVE_SPATIAL count+= native_func_registry_array_geom.count(); #endif - if (my_hash_init(& native_functions_hash, - system_charset_info, - (ulong) count, - 0, - 0, - (my_hash_get_key) get_native_fct_hash_key, - NULL, /* Nothing to free */ - MYF(0))) + if (my_hash_init(key_memory_native_functions, & native_functions_hash, + system_charset_info, (ulong) count, 0, 0, (my_hash_get_key) + get_native_fct_hash_key, NULL, MYF(0))) DBUG_RETURN(1); if (native_func_registry_array.append_to_hash(&native_functions_hash)) diff --git a/sql/item_func.cc b/sql/item_func.cc index 0419d55cc58..57ef5d6adb9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4019,16 +4019,17 @@ longlong Item_func_get_lock::val_int() DBUG_PRINT("enter", ("lock: %.*s", res->length(), res->ptr())); /* HASH entries are of type User_level_lock. */ if (! my_hash_inited(&thd->ull_hash) && - my_hash_init(&thd->ull_hash, &my_charset_bin, - 16 /* small hash */, 0, 0, ull_get_key, NULL, 0)) + my_hash_init(key_memory_User_level_lock, &thd->ull_hash, + &my_charset_bin, 16 /* small hash */, 0, 0, ull_get_key, + NULL, 0)) { DBUG_RETURN(0); } MDL_request ull_request; - ull_request.init(MDL_key::USER_LOCK, res->c_ptr_safe(), "", + MDL_REQUEST_INIT(&ull_request, MDL_key::USER_LOCK, res->c_ptr_safe(), "", MDL_SHARED_NO_WRITE, MDL_EXPLICIT); - MDL_key *ull_key = &ull_request.key; + MDL_key *ull_key= &ull_request.key; if ((ull= (User_level_lock*) @@ -4036,7 +4037,7 @@ longlong Item_func_get_lock::val_int() { /* Recursive lock */ ull->refs++; - null_value = 0; + null_value= 0; DBUG_PRINT("info", ("recursive lock, ref-count: %d", (int) ull->refs)); DBUG_RETURN(1); } @@ -4052,7 +4053,8 @@ longlong Item_func_get_lock::val_int() DBUG_RETURN(0); } - ull= (User_level_lock*) my_malloc(sizeof(User_level_lock), + ull= (User_level_lock*) my_malloc(key_memory_User_level_lock, + sizeof(User_level_lock), MYF(MY_WME|MY_THREAD_SPECIFIC)); if (ull == NULL) { @@ -4076,6 +4078,30 @@ longlong Item_func_get_lock::val_int() /** + Release all user level locks. + @return + - N if N-lock released + - 0 if lock wasn't held +*/ +longlong Item_func_release_all_locks::val_int() +{ + DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + ulong num_unlocked= 0; + DBUG_ENTER("Item_func_release_all_locks::val_int"); + for (size_t i= 0; i < thd->ull_hash.records; i++) + { + auto ull= (User_level_lock *) my_hash_element(&thd->ull_hash, i); + thd->mdl_context.release_lock(ull->lock); + num_unlocked+= ull->refs; + my_free(ull); + } + my_hash_free(&thd->ull_hash); + DBUG_RETURN(num_unlocked); +} + + +/** Release a user level lock. @return - 1 if lock released @@ -4275,7 +4301,7 @@ static PSI_mutex_key key_LOCK_item_func_sleep; static PSI_mutex_info item_func_sleep_mutexes[]= { - { &key_LOCK_item_func_sleep, "LOCK_user_locks", PSI_FLAG_GLOBAL} + { &key_LOCK_item_func_sleep, "LOCK_item_func_sleep", PSI_FLAG_GLOBAL} }; @@ -4396,7 +4422,7 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name, size_t size=ALIGN_SIZE(sizeof(user_var_entry))+name->length+1+extra_size; if (!my_hash_inited(hash)) return 0; - if (!(entry = (user_var_entry*) my_malloc(size, + if (!(entry = (user_var_entry*) my_malloc(key_memory_user_var_entry, size, MYF(MY_WME | ME_FATAL | MY_THREAD_SPECIFIC)))) return 0; @@ -4656,10 +4682,10 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); if (entry->value == pos) entry->value=0; - entry->value= (char*) my_realloc(entry->value, length, + entry->value= (char*) my_realloc(key_memory_user_var_entry_value, + entry->value, length, MYF(MY_ALLOW_ZERO_PTR | MY_WME | - ME_FATAL | - MY_THREAD_SPECIFIC)); + ME_FATAL | MY_THREAD_SPECIFIC)); if (!entry->value) return 1; } @@ -6770,7 +6796,7 @@ longlong Item_func_nextval::val_int() if (!(entry= ((SEQUENCE_LAST_VALUE*) my_hash_search(&thd->sequences, (uchar*) key, length)))) { - if (!(key= (char*) my_memdup(key, length, MYF(MY_WME))) || + if (!(key= (char*) my_memdup(PSI_INSTRUMENT_ME, key, length, MYF(MY_WME))) || !(entry= new SEQUENCE_LAST_VALUE((uchar*) key, length))) { /* EOM, error given */ diff --git a/sql/item_func.h b/sql/item_func.h index dced158bb86..3771992d617 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2654,19 +2654,13 @@ public: void mysql_ull_cleanup(THD *thd); void mysql_ull_set_explicit_lock_duration(THD *thd); -class Item_func_get_lock :public Item_long_func + +class Item_func_lock :public Item_long_func { - bool check_arguments() const - { - return args[0]->check_type_general_purpose_string(func_name()) || - args[1]->check_type_can_return_real(func_name()); - } - String value; public: - Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} - longlong val_int(); - const char *func_name() const { return "get_lock"; } - bool fix_length_and_dec() { max_length=1; maybe_null=1; return FALSE; } + Item_func_lock(THD *thd): Item_long_func(thd) { } + Item_func_lock(THD *thd, Item *a): Item_long_func(thd, a) {} + Item_func_lock(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@ -2677,34 +2671,54 @@ class Item_func_get_lock :public Item_long_func { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd) +}; + + +class Item_func_get_lock final :public Item_func_lock +{ + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + args[1]->check_type_can_return_real(func_name()); + } + String value; + public: + Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_func_lock(thd, a, b) {} + longlong val_int() final; + const char *func_name() const final { return "get_lock"; } + bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; } + Item *get_copy(THD *thd) final { return get_item_copy<Item_func_get_lock>(thd, this); } }; -class Item_func_release_lock :public Item_long_func + +class Item_func_release_all_locks final :public Item_func_lock +{ +public: + Item_func_release_all_locks(THD *thd): Item_func_lock(thd) + { unsigned_flag= 1; } + longlong val_int() final; + const char *func_name() const final { return "release_all_locks"; } + Item *get_copy(THD *thd) final + { return get_item_copy<Item_func_release_all_locks>(thd, this); } +}; + + +class Item_func_release_lock final :public Item_func_lock { bool check_arguments() const { return args[0]->check_type_general_purpose_string(func_name()); } String value; public: - Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {} - longlong val_int(); + Item_func_release_lock(THD *thd, Item *a): Item_func_lock(thd, a) {} + longlong val_int() final; const char *func_name() const { return "release_lock"; } bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; } - table_map used_tables() const - { - return used_tables_cache | RAND_TABLE_BIT; - } - bool const_item() const { return 0; } - bool is_expensive() { return 1; } - bool check_vcol_func_processor(void *arg) - { - return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); - } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) final { return get_item_copy<Item_func_release_lock>(thd, this); } }; + /* replication functions */ class Item_master_pos_wait :public Item_longlong_func diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index e61d0875056..44f9e8146c2 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -84,6 +84,11 @@ public: maybe_null= 1; return FALSE; } + bool set_format_by_check_constraint(Send_field_extended_metadata *to) const + { + static const Lex_cstring fmt(STRING_WITH_LEN("json")); + return to->set_format_name(fmt); + } Item *get_copy(THD *thd) { return get_item_copy<Item_func_json_valid>(thd, this); } }; @@ -118,6 +123,12 @@ public: Item_json_func(THD *thd, List<Item> &list) :Item_str_func(thd, list) { } bool is_json_type() { return true; } + void make_send_field(THD *thd, Send_field *tmp_field) + { + Item_str_func::make_send_field(thd, tmp_field); + static const Lex_cstring fmt(STRING_WITH_LEN("json")); + tmp_field->set_format_name(fmt); + } }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index bee56a607f7..bcc041ae9c6 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -43,7 +43,6 @@ #include "set_var.h" #include "sql_base.h" #include "sql_time.h" -#include "sql_acl.h" // SUPER_ACL #include "des_key_file.h" // st_des_keyschedule, st_des_keyblock #include "password.h" // my_make_scrambled_password, // my_make_scrambled_password_323 @@ -838,7 +837,7 @@ String *Item_func_des_decrypt::val_str(String *str) { uint key_number=(uint) (*res)[0] & 127; // Check if automatic key and that we have privilege to uncompress using it - if (!(current_thd->security_ctx->master_access & SUPER_ACL) || + if (!(current_thd->security_ctx->master_access & PRIV_DES_DECRYPT_ONE_ARG) || key_number > 9) goto error; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2d3ea388cc5..e494e9d84e1 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4434,9 +4434,10 @@ void subselect_single_select_engine::print(String *str, enum_query_type query_type) { With_clause* with_clause= select_lex->get_with_clause(); + THD *thd= get_thd(); if (with_clause) - with_clause->print(str, query_type); - select_lex->print(get_thd(), str, query_type); + with_clause->print(thd, str, query_type); + select_lex->print(thd, str, query_type); } @@ -5807,8 +5808,9 @@ bool Ordered_key::alloc_keys_buffers() { DBUG_ASSERT(key_buff_elements > 0); - if (!(key_buff= (rownum_t*) my_malloc((size_t)(key_buff_elements * - sizeof(rownum_t)), MYF(MY_WME | MY_THREAD_SPECIFIC)))) + if (!(key_buff= (rownum_t*) my_malloc(PSI_INSTRUMENT_ME, + static_cast<size_t>(key_buff_elements * sizeof(rownum_t)), + MYF(MY_WME | MY_THREAD_SPECIFIC)))) return TRUE; /* @@ -6239,8 +6241,9 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, sizeof(Ordered_key*))) || !(null_bitmaps= (MY_BITMAP**) thd->alloc(merge_keys_count * sizeof(MY_BITMAP*))) || - !(row_num_to_rowid= (uchar*) my_malloc((size_t)(row_count * rowid_length), - MYF(MY_WME | MY_THREAD_SPECIFIC)))) + !(row_num_to_rowid= (uchar*) my_malloc(PSI_INSTRUMENT_ME, + static_cast<size_t>(row_count * rowid_length), + MYF(MY_WME | MY_THREAD_SPECIFIC)))) return TRUE; /* Create the only non-NULL key if there is any. */ diff --git a/sql/keycaches.cc b/sql/keycaches.cc index 60049cdd67d..10bec7c1de8 100644 --- a/sql/keycaches.cc +++ b/sql/keycaches.cc @@ -23,6 +23,9 @@ NAMED_ILIST key_caches; NAMED_ILIST rpl_filters; +extern "C" PSI_memory_key key_memory_KEY_CACHE; +extern PSI_memory_key key_memory_NAMED_ILINK_name; + /** ilink (intrusive list element) with a name */ @@ -37,7 +40,8 @@ public: size_t name_length_arg, uchar* data_arg) :name_length(name_length_arg), data(data_arg) { - name= my_strndup(name_arg, name_length, MYF(MY_WME)); + name= my_strndup(key_memory_NAMED_ILINK_name, name_arg, name_length, + MYF(MY_WME)); links->push_back(this); } inline bool cmp(const char *name_cmp, size_t length) @@ -118,8 +122,8 @@ KEY_CACHE *create_key_cache(const char *name, size_t length) DBUG_ENTER("create_key_cache"); DBUG_PRINT("enter",("name: %.*s", (int)length, name)); - if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE), - MYF(MY_ZEROFILL | MY_WME)))) + if ((key_cache= (KEY_CACHE*) my_malloc(key_memory_KEY_CACHE, + sizeof(KEY_CACHE), MYF(MY_ZEROFILL | MY_WME)))) { if (!new NAMED_ILINK(&key_caches, name, length, (uchar*) key_cache)) { diff --git a/sql/lex.h b/sql/lex.h index 1cb7ad5d4c8..f36b8258c93 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -239,6 +239,7 @@ static SYMBOL symbols[] = { { "FALSE", SYM(FALSE_SYM)}, { "FAST", SYM(FAST_SYM)}, { "FAULTS", SYM(FAULTS_SYM)}, + { "FEDERATED", SYM(FEDERATED_SYM)}, { "FETCH", SYM(FETCH_SYM)}, { "FIELDS", SYM(COLUMNS)}, { "FILE", SYM(FILE_SYM)}, @@ -405,6 +406,7 @@ static SYMBOL symbols[] = { { "MODE", SYM(MODE_SYM)}, { "MODIFIES", SYM(MODIFIES_SYM)}, { "MODIFY", SYM(MODIFY_SYM)}, + { "MONITOR", SYM(MONITOR_SYM)}, { "MONTH", SYM(MONTH_SYM)}, { "MUTEX", SYM(MUTEX_SYM)}, { "MYSQL", SYM(MYSQL_SYM)}, diff --git a/sql/lock.cc b/sql/lock.cc index 6f86c0a38f6..7f69946c35e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -76,7 +76,6 @@ #include "lock.h" #include "sql_base.h" // close_tables_for_reopen #include "sql_parse.h" // is_log_table_write_query -#include "sql_acl.h" // SUPER_ACL #include "sql_handler.h" #include <hash.h> #include "wsrep_mysqld.h" @@ -109,12 +108,13 @@ static int lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) { uint system_count, i; - bool is_superuser, log_table_write_query; + bool ignore_read_only, log_table_write_query; DBUG_ENTER("lock_tables_check"); system_count= 0; - is_superuser= (thd->security_ctx->master_access & SUPER_ACL) != NO_ACL; + ignore_read_only= + (thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) != NO_ACL; log_table_write_query= (is_log_table_write_query(thd->lex->sql_command) || ((flags & MYSQL_LOCK_LOG_TABLE) != 0)); @@ -179,7 +179,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table) { if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE && - !is_superuser && opt_readonly && !thd->slave_thread) + !ignore_read_only && opt_readonly && !thd->slave_thread) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); DBUG_RETURN(1); @@ -645,7 +645,7 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) a->lock_count, b->lock_count)); if (!(sql_lock= (MYSQL_LOCK*) - my_malloc(sizeof(*sql_lock)+ + my_malloc(key_memory_MYSQL_LOCK, sizeof(*sql_lock) + sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) + sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME)))) DBUG_RETURN(0); // Fatal error @@ -764,7 +764,8 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags) sizeof(table_ptr) * table_count; if (!(sql_lock= (MYSQL_LOCK*) (flags & GET_LOCK_ON_THD ? thd->alloc(amount) : - my_malloc(amount, MYF(0))))) + my_malloc(key_memory_MYSQL_LOCK, amount, + MYF(0))))) DBUG_RETURN(0); locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1); to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2); @@ -858,8 +859,10 @@ bool lock_schema_name(THD *thd, const char *db) if (thd->has_read_only_protection()) return TRUE; - global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT); - mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, + MDL_STATEMENT); + MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, + MDL_TRANSACTION); mdl_requests.push_front(&mdl_request); mdl_requests.push_front(&global_request); @@ -916,10 +919,12 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type, if (thd->has_read_only_protection()) return TRUE; - global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT); - schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE, - MDL_TRANSACTION); - mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, + MDL_STATEMENT); + MDL_REQUEST_INIT(&schema_request, MDL_key::SCHEMA, db, "", + MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&mdl_request, mdl_type, db, name, MDL_EXCLUSIVE, + MDL_TRANSACTION); mdl_requests.push_front(&mdl_request); mdl_requests.push_front(&schema_request); @@ -1040,7 +1045,7 @@ bool Global_read_lock::lock_global_read_lock(THD *thd) MDL_BACKUP_FTWRL1)); DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::BACKUP, "", "", MDL_BACKUP_FTWRL2)); - mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_FTWRL1, + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_FTWRL1, MDL_EXPLICIT); do diff --git a/sql/log.cc b/sql/log.cc index 56e83bf2448..355118dc701 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -34,7 +34,6 @@ #include "sql_parse.h" // command_name #include "sql_time.h" // calc_time_from_sec, my_time_compare #include "tztime.h" // my_tz_OFFSET0, struct Time_zone -#include "sql_acl.h" // SUPER_ACL #include "log_event.h" // Query_log_event #include "rpl_filter.h" #include "rpl_rli.h" @@ -253,7 +252,7 @@ void make_default_log_name(char **out, const char* log_ext, bool once) else { my_free(*out); - *out= my_strdup(buff, MYF(MY_WME)); + *out= my_strdup(PSI_INSTRUMENT_ME, buff, MYF(MY_WME)); } } @@ -1723,7 +1722,8 @@ static int binlog_close_connection(handlerton *hton, THD *thd) if (len > 0) wsrep_dump_rbr_buf(thd, buf, len); } #endif /* WITH_WSREP */ - DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty()); + DBUG_ASSERT(cache_mngr->trx_cache.empty()); + DBUG_ASSERT(cache_mngr->stmt_cache.empty()); cache_mngr->~binlog_cache_mngr(); my_free(cache_mngr); DBUG_RETURN(0); @@ -2211,8 +2211,8 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional) if (WSREP_EMULATE_BINLOG(thd)) { if (is_transactional) - trans_register_ha(thd, TRUE, binlog_hton); - trans_register_ha(thd, FALSE, binlog_hton); + trans_register_ha(thd, TRUE, binlog_hton, 0); + trans_register_ha(thd, FALSE, binlog_hton, 0); } #endif /* WITH_WSREP */ DBUG_VOID_RETURN; @@ -2412,8 +2412,8 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg) *errmsg = "Could not open log file"; goto err; } - if (init_io_cache(log, file, (size_t)binlog_file_cache_size, READ_CACHE, 0, 0, - MYF(MY_WME|MY_DONT_CHECK_FILESIZE))) + if (init_io_cache_ext(log, file, (size_t)binlog_file_cache_size, READ_CACHE, + 0, 0, MYF(MY_WME|MY_DONT_CHECK_FILESIZE), key_file_binlog_cache)) { sql_print_error("Failed to create a cache on log (file '%s')", log_file_name); @@ -2652,7 +2652,7 @@ bool MYSQL_LOG::open( write_error= 0; - if (!(name= my_strdup(log_name, MYF(MY_WME)))) + if (!(name= my_strdup(key_memory_MYSQL_LOG_name, log_name, MYF(MY_WME)))) { name= (char *)log_name; // for the error message goto err; @@ -3392,10 +3392,11 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC, MYF(MY_WME))) < 0 || mysql_file_sync(index_file_nr, MYF(MY_WME)) || - init_io_cache(&index_file, index_file_nr, + init_io_cache_ext(&index_file, index_file_nr, IO_SIZE, WRITE_CACHE, mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)), - 0, MYF(MY_WME | MY_WAIT_IF_FULL)) || + 0, MYF(MY_WME | MY_WAIT_IF_FULL), + m_key_file_log_index_cache) || DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) { /* @@ -4442,14 +4443,16 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) { rli->last_inuse_relaylog= NULL; included= 1; - to_purge_if_included= my_strdup(ir->name, MYF(0)); + to_purge_if_included= my_strdup(key_memory_Relay_log_info_group_relay_log_name, + ir->name, MYF(0)); } rli->free_inuse_relaylog(ir); ir= next; } rli->inuse_relaylog_list= ir; if (ir) - to_purge_if_included= my_strdup(ir->name, MYF(0)); + to_purge_if_included= my_strdup(key_memory_Relay_log_info_group_relay_log_name, + ir->name, MYF(0)); /* Read the next log file name from the index file and pass it back to @@ -5588,7 +5591,8 @@ binlog_cache_mngr *THD::binlog_setup_trx_data() if (cache_mngr) DBUG_RETURN(cache_mngr); // Already set up - cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL)); + cache_mngr= (binlog_cache_mngr*) my_malloc(key_memory_binlog_cache_mngr, + sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL)); if (!cache_mngr || open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir, LOG_PREFIX, (size_t)binlog_stmt_cache_size, MYF(MY_WME)) || @@ -5708,8 +5712,8 @@ THD::binlog_start_trans_and_stmt() } #endif if (mstmt_mode) - trans_register_ha(this, TRUE, binlog_hton); - trans_register_ha(this, FALSE, binlog_hton); + trans_register_ha(this, TRUE, binlog_hton, 0); + trans_register_ha(this, FALSE, binlog_hton, 0); /* Mark statement transaction as read/write. We never start a binary log transaction and keep it read-only, @@ -5753,7 +5757,7 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd) strmake_buf(cache_mngr->last_commit_pos_file, mysql_bin_log.last_commit_pos_file); cache_mngr->last_commit_pos_offset= mysql_bin_log.last_commit_pos_offset; - trans_register_ha(thd, TRUE, hton); + trans_register_ha(thd, TRUE, binlog_hton, 0); DBUG_RETURN(err); } @@ -9108,7 +9112,8 @@ int TC_LOG_MMAP::open(const char *opt_name) npages=(uint)file_length/tc_log_page_size; if (npages < 3) // to guarantee non-empty pool goto err; - if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL)))) + if (!(pages=(PAGE *)my_malloc(key_memory_TC_LOG_MMAP_pages, + npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL)))) goto err; inited=3; for (pg=pages, i=0; i < npages; i++, pg++) @@ -9418,7 +9423,8 @@ int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) { uint32 size= sizeof(*pending_checkpoint) + sizeof(ulong) * (ncookies - 1); if (!(pending_checkpoint= - (pending_cookies *)my_malloc(size, MYF(MY_ZEROFILL)))) + (pending_cookies *)my_malloc(PSI_INSTRUMENT_ME, size, + MYF(MY_ZEROFILL)))) { my_error(ER_OUTOFMEMORY, MYF(0), size); mysql_mutex_unlock(&LOCK_pending_checkpoint); @@ -9557,8 +9563,8 @@ int TC_LOG_MMAP::recover() goto err1; } - if (my_hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0, - sizeof(my_xid), 0, 0, MYF(0))) + if (my_hash_init(PSI_INSTRUMENT_ME, &xids, &my_charset_bin, + tc_log_page_size/3, 0, sizeof(my_xid), 0, 0, MYF(0))) goto err1; for ( ; p < end_p ; p++) @@ -10071,13 +10077,13 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, #endif if (! fdle->is_valid() || - (do_xa && my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0, + (do_xa && my_hash_init(key_memory_binlog_recover_exec, &xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0, sizeof(my_xid), 0, 0, MYF(0)))) goto err1; if (do_xa) - init_alloc_root(&mem_root, "TC_LOG_BINLOG", TC_LOG_PAGE_SIZE, - TC_LOG_PAGE_SIZE, MYF(0)); + init_alloc_root(key_memory_binlog_recover_exec, &mem_root, + TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE, MYF(0)); fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error @@ -10489,7 +10495,7 @@ static struct st_mysql_sys_var *binlog_sys_vars[]= /* Copy out the non-directory part of binlog position filename for the `binlog_snapshot_file' status variable, same way as it is done for - SHOW MASTER STATUS. + SHOW BINLOG STATUS. */ static void set_binlog_snapshot_file(const char *src) @@ -10741,8 +10747,8 @@ void wsrep_register_binlog_handler(THD *thd, bool trx) Set callbacks in order to be able to call commmit or rollback. */ if (trx) - trans_register_ha(thd, TRUE, binlog_hton); - trans_register_ha(thd, FALSE, binlog_hton); + trans_register_ha(thd, TRUE, binlog_hton, 0); + trans_register_ha(thd, FALSE, binlog_hton, 0); /* Set the binary log as read/write otherwise callbacks are not called. diff --git a/sql/log.h b/sql/log.h index 8684eaba786..e4424778111 100644 --- a/sql/log.h +++ b/sql/log.h @@ -412,7 +412,6 @@ struct wait_for_commit; class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG { -#ifdef HAVE_PSI_INTERFACE /** The instrumentation key to use for @ LOCK_index. */ PSI_mutex_key m_key_LOCK_index; /** The instrumentation key to use for @ COND_relay_log_updated */ @@ -420,14 +419,13 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG /** The instrumentation key to use for @ COND_bin_log_updated */ PSI_cond_key m_key_bin_log_update; /** The instrumentation key to use for opening the log file. */ - PSI_file_key m_key_file_log; + PSI_file_key m_key_file_log, m_key_file_log_cache; /** The instrumentation key to use for opening the log index file. */ - PSI_file_key m_key_file_log_index; + PSI_file_key m_key_file_log_index, m_key_file_log_index_cache; - PSI_file_key m_key_COND_queue_busy; + PSI_cond_key m_key_COND_queue_busy; /** The instrumentation key to use for LOCK_binlog_end_pos. */ PSI_mutex_key m_key_LOCK_binlog_end_pos; -#endif struct group_commit_entry { @@ -587,7 +585,7 @@ public: :binlog_id(0), xid_count(0), notify_count(0) { binlog_name_len= log_file_name_len; - binlog_name= (char *) my_malloc(binlog_name_len, MYF(MY_ZEROFILL)); + binlog_name= (char *) my_malloc(PSI_INSTRUMENT_ME, binlog_name_len, MYF(MY_ZEROFILL)); if (binlog_name) memcpy(binlog_name, log_file_name, binlog_name_len); } @@ -674,15 +672,19 @@ public: PSI_cond_key key_relay_log_update, PSI_cond_key key_bin_log_update, PSI_file_key key_file_log, + PSI_file_key key_file_log_cache, PSI_file_key key_file_log_index, - PSI_file_key key_COND_queue_busy, + PSI_file_key key_file_log_index_cache, + PSI_cond_key key_COND_queue_busy, PSI_mutex_key key_LOCK_binlog_end_pos) { m_key_LOCK_index= key_LOCK_index; m_key_relay_log_update= key_relay_log_update; m_key_bin_log_update= key_bin_log_update; m_key_file_log= key_file_log; + m_key_file_log_cache= key_file_log_cache; m_key_file_log_index= key_file_log_index; + m_key_file_log_index_cache= key_file_log_index_cache; m_key_COND_queue_busy= key_COND_queue_busy; m_key_LOCK_binlog_end_pos= key_LOCK_binlog_end_pos; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 4c1c18fffff..7ee38a007d1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -56,6 +56,10 @@ #define my_b_write_string(A, B) my_b_write((A), (uchar*)(B), (uint) (sizeof(B) - 1)) +PSI_memory_key key_memory_log_event; +PSI_memory_key key_memory_Incident_log_event_message; +PSI_memory_key key_memory_Rows_query_log_event_rows_query; + /** BINLOG_CHECKSUM variable. */ @@ -410,7 +414,7 @@ query_event_uncompress(const Format_description_log_event *description_event, } else { - new_dst = (char *)my_malloc(alloc_size, MYF(MY_WME)); + new_dst = (char *)my_malloc(PSI_INSTRUMENT_ME, alloc_size, MYF(MY_WME)); if (!new_dst) return 1; @@ -532,7 +536,7 @@ row_log_event_uncompress(const Format_description_log_event *description_event, } else { - new_dst = (char *)my_malloc(alloc_size, MYF(MY_WME)); + new_dst = (char *)my_malloc(PSI_INSTRUMENT_ME, alloc_size, MYF(MY_WME)); if (!new_dst) return 1; @@ -873,7 +877,7 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet, */ sz += MY_AES_BLOCK_SIZE; #endif - char *newpkt= (char*)my_malloc(sz, MYF(MY_WME)); + char *newpkt= (char*)my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME)); if (!newpkt) DBUG_RETURN(LOG_READ_MEM); memcpy(newpkt, packet->ptr(), ev_offset); @@ -1665,7 +1669,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, */ #if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + if (!(start= data_buf = (Log_event::Byte*) my_malloc(PSI_INSTRUMENT_ME, + catalog_len + 1 + time_zone_len + 1 + user.length + 1 + host.length + 1 @@ -1676,7 +1681,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, + QUERY_CACHE_FLAGS_SIZE, MYF(MY_WME)))) #else - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + if (!(start= data_buf = (Log_event::Byte*) my_malloc(PSI_INSTRUMENT_ME, + catalog_len + 1 + time_zone_len + 1 + user.length + 1 + host.length + 1 @@ -1783,8 +1789,8 @@ Query_compressed_log_event::Query_compressed_log_event(const char *buf, } /* Reserve one byte for '\0' */ - query_buf = (Log_event::Byte*)my_malloc(ALIGN_SIZE(un_len + 1), - MYF(MY_WME)); + query_buf = (Log_event::Byte*)my_malloc(PSI_INSTRUMENT_ME, + ALIGN_SIZE(un_len + 1), MYF(MY_WME)); if(query_buf && !binlog_buf_uncompress(query, (char *)query_buf, q_len, &un_len)) { @@ -2033,7 +2039,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) common_header_len= LOG_EVENT_HEADER_LEN; number_of_event_types= LOG_EVENT_TYPES; /* we'll catch my_malloc() error in is_valid() */ - post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8) + post_header_len=(uint8*) my_malloc(PSI_INSTRUMENT_ME, + number_of_event_types*sizeof(uint8) + BINLOG_CHECKSUM_ALG_DESC_LEN, MYF(0)); /* @@ -2159,8 +2166,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) make the slave detect less corruptions). */ number_of_event_types= FORMAT_DESCRIPTION_EVENT - 1; - post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8), - MYF(0)); + post_header_len=(uint8*) my_malloc(PSI_INSTRUMENT_ME, + number_of_event_types*sizeof(uint8), MYF(0)); if (post_header_len) { post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN; @@ -2228,7 +2235,8 @@ Format_description_log_event(const char* buf, common_header_len, number_of_event_types)); /* If alloc fails, we'll detect it in is_valid() */ - post_header_len= (uint8*) my_memdup((uchar*)buf+ST_COMMON_HEADER_LEN_OFFSET+1, + post_header_len= (uint8*) my_memdup(PSI_INSTRUMENT_ME, + buf+ST_COMMON_HEADER_LEN_OFFSET+1, number_of_event_types* sizeof(*post_header_len), MYF(0)); @@ -2517,7 +2525,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, ident_len= (uint)(event_len - (LOG_EVENT_MINIMAL_HEADER_LEN + post_header_len)); ident_offset= post_header_len; set_if_smaller(ident_len,FN_REFLEN-1); - new_log_ident= my_strndup(buf + ident_offset, (uint) ident_len, MYF(MY_WME)); + new_log_ident= my_strndup(PSI_INSTRUMENT_ME, buf + ident_offset, (uint) ident_len, MYF(MY_WME)); DBUG_PRINT("debug", ("new_log_ident: '%s'", new_log_ident)); DBUG_VOID_RETURN; } @@ -2544,7 +2552,7 @@ Binlog_checkpoint_log_event::Binlog_checkpoint_log_event( binlog_file_len= uint4korr(buf); if (event_len - (header_size + post_header_len) < binlog_file_len) return; - binlog_file_name= my_strndup(buf + post_header_len, binlog_file_len, + binlog_file_name= my_strndup(PSI_INSTRUMENT_ME, buf + post_header_len, binlog_file_len, MYF(MY_WME)); return; } @@ -2603,8 +2611,8 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len, gl_flags= val & ((uint32)0xf << 28); buf+= 4; if (event_len - (header_size + post_header_len) < count*element_size || - (!(list= (rpl_gtid *)my_malloc(count*sizeof(*list) + (count == 0), - MYF(MY_WME))))) + (!(list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + count*sizeof(*list) + (count == 0), MYF(MY_WME))))) return; for (i= 0; i < count; ++i) @@ -2621,7 +2629,8 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len, if ((gl_flags & FLAG_IGN_GTIDS)) { uint32 i; - if (!(sub_id_list= (uint64 *)my_malloc(count*sizeof(uint64), MYF(MY_WME)))) + if (!(sub_id_list= (uint64 *)my_malloc(PSI_INSTRUMENT_ME, + count*sizeof(uint64), MYF(MY_WME)))) { my_free(list); list= NULL; @@ -2678,8 +2687,8 @@ Gtid_list_log_event::peek(const char *event_start, size_t event_len, if (event_len < (uint32)fdev->common_header_len + GTID_LIST_HEADER_LEN + 16 * count) return true; - if (!(gtid_list= (rpl_gtid *)my_malloc(sizeof(rpl_gtid)*count + (count == 0), - MYF(MY_WME)))) + if (!(gtid_list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(rpl_gtid)*count + (count == 0), MYF(MY_WME)))) return true; *out_gtid_list= gtid_list; *out_list_len= count; @@ -2886,7 +2895,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len, uint header_len= description_event->common_header_len; uint8 load_header_len= description_event->post_header_len[LOAD_EVENT-1]; uint8 create_file_header_len= description_event->post_header_len[CREATE_FILE_EVENT-1]; - if (!(event_buf= (char*) my_memdup(buf, len, MYF(MY_WME))) || + if (!(event_buf= (char*) my_memdup(PSI_INSTRUMENT_ME, buf, len, MYF(MY_WME))) || copy_log_event(event_buf,len, (((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ? load_header_len + header_len : @@ -3188,7 +3197,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, /* Just store/use the first tag of this type, skip others */ if (likely(!m_extra_row_data)) { - m_extra_row_data= (uchar*) my_malloc(infoLen, + m_extra_row_data= (uchar*) my_malloc(PSI_INSTRUMENT_ME, infoLen, MYF(MY_WME)); if (likely(m_extra_row_data != NULL)) { @@ -3277,7 +3286,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, DBUG_PRINT("info",("m_table_id: %llu m_flags: %d m_width: %lu data_size: %lu", m_table_id, m_flags, m_width, (ulong) data_size)); - m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); + m_rows_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, data_size, MYF(MY_WME)); if (likely((bool)m_rows_buf)) { #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) @@ -3300,7 +3309,7 @@ void Rows_log_event::uncompress_buf() if (!un_len) return; - uchar *new_buf= (uchar*) my_malloc(ALIGN_SIZE(un_len), MYF(MY_WME)); + uchar *new_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, ALIGN_SIZE(un_len), MYF(MY_WME)); if (new_buf) { if(!binlog_buf_uncompress((char *)m_rows_buf, (char *)new_buf, @@ -3535,7 +3544,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, m_colcnt, (long) (ptr_colcnt-(const uchar*)vpart))); /* Allocate mem for all fields in one go. If fails, caught in is_valid() */ - m_memory= (uchar*) my_multi_malloc(MYF(MY_WME), + m_memory= (uchar*) my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &m_dbnam, (uint) m_dblen + 1, &m_tblnam, (uint) m_tbllen + 1, &m_coltype, (uint) m_colcnt, @@ -3554,7 +3563,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, if (m_field_metadata_size <= (m_colcnt * 2)) { uint num_null_bytes= (m_colcnt + 7) / 8; - m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), + m_meta_memory= (uchar *)my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &m_null_bits, num_null_bytes, &m_field_metadata, m_field_metadata_size, NULL); @@ -3578,7 +3587,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, { m_optional_metadata_len= event_len - bytes_read; m_optional_metadata= - static_cast<unsigned char*>(my_malloc(m_optional_metadata_len, MYF(MY_WME))); + static_cast<unsigned char*>(my_malloc(PSI_INSTRUMENT_ME, m_optional_metadata_len, MYF(MY_WME))); memcpy(m_optional_metadata, ptr_after_colcnt, m_optional_metadata_len); } } @@ -3958,7 +3967,7 @@ Incident_log_event::Incident_log_event(const char *buf, uint event_len, m_incident= INCIDENT_NONE; DBUG_VOID_RETURN; } - if (!(m_message.str= (char*) my_malloc(len+1, MYF(MY_WME)))) + if (!(m_message.str= (char*) my_malloc(key_memory_log_event, len+1, MYF(MY_WME)))) { /* Mark this event invalid */ m_incident= INCIDENT_NONE; diff --git a/sql/log_event.h b/sql/log_event.h index 15442bd5a97..67cf27b60a0 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1357,7 +1357,8 @@ public: static void *operator new(size_t size) { - return (void*) my_malloc((uint)size, MYF(MY_WME|MY_FAE)); + extern PSI_memory_key key_memory_log_event; + return my_malloc(key_memory_log_event, size, MYF(MY_WME|MY_FAE)); } static void operator delete(void *ptr, size_t) @@ -4880,6 +4881,12 @@ public: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) virtual uint8 get_trg_event_map()= 0; + + inline bool do_invoke_trigger() + { + return (slave_run_triggers_for_rbr && !master_had_triggers) || + slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE; + } #endif protected: @@ -5362,11 +5369,12 @@ public: Incident_log_event(THD *thd_arg, Incident incident, const LEX_CSTRING *msg) : Log_event(thd_arg, 0, FALSE), m_incident(incident) { + extern PSI_memory_key key_memory_Incident_log_event_message; DBUG_ENTER("Incident_log_event::Incident_log_event"); DBUG_PRINT("enter", ("m_incident: %d", m_incident)); m_message.length= 0; - if (unlikely(!(m_message.str= (char*) my_malloc(msg->length+1, - MYF(MY_WME))))) + if (!(m_message.str= (char*) my_malloc(key_memory_Incident_log_event_message, + msg->length + 1, MYF(MY_WME)))) { /* Mark this event invalid */ m_incident= INCIDENT_NONE; diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index cae4842355a..6ee5587943d 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -1104,7 +1104,7 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf if (((get_general_type_code() == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end))) goto end; - (void) my_init_dynamic_array(&rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0)); + (void) my_init_dynamic_array(PSI_NOT_INSTRUMENTED, &rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0)); for (uchar *value= m_rows_buf; value < m_rows_end; ) { @@ -1119,7 +1119,7 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf } value+= length1; - swap_buff1= (uchar *) my_malloc(length1, MYF(0)); + swap_buff1= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED, length1, MYF(0)); if (!swap_buff1) { fprintf(stderr, "\nError: Out of memory. " @@ -1142,7 +1142,7 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf } value+= length2; - swap_buff2= (uchar *) my_malloc(length2, MYF(0)); + swap_buff2= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED, length2, MYF(0)); if (!swap_buff2) { fprintf(stderr, "\nError: Out of memory. " @@ -1170,7 +1170,7 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf LEX_STRING one_row; one_row.length= length1 + length2; - one_row.str= (char *) my_malloc(one_row.length, MYF(0)); + one_row.str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, one_row.length, MYF(0)); memcpy(one_row.str, start_pos, one_row.length); if (one_row.str == NULL || push_dynamic(&rows_arr, (uchar *) &one_row)) { @@ -1637,7 +1637,7 @@ bool Log_event::print_base64(IO_CACHE* file, { size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size); char *tmp_str; - if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME)))) + if (!(tmp_str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, tmp_str_sz, MYF(MY_WME)))) goto err; if (my_base64_encode(ptr, (size_t) size, tmp_str)) @@ -2491,7 +2491,7 @@ bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) bool error; // 2 hex digits / byte - hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME)); + hex_str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, 2 * val_len + 1 + 3, MYF(MY_WME)); if (!hex_str) goto err; str_to_hex(hex_str, val, val_len); @@ -2853,7 +2853,7 @@ bool copy_cache_to_string_wrapped(IO_CACHE *cache, if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE)) goto err; - if (!(to->str= (char*) my_malloc((size_t)cache->end_of_file + fmt_size, + if (!(to->str= (char*) my_malloc(PSI_NOT_INSTRUMENTED, (size_t)cache->end_of_file + fmt_size, MYF(0)))) { perror("Out of memory: can't allocate memory in " @@ -3108,7 +3108,7 @@ int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len, // Create new temp_buf ulong event_cur_len= uint4korr(temp_buf + EVENT_LEN_OFFSET); ulong event_new_len= event_cur_len + len_diff; - char* new_temp_buf= (char*) my_malloc(event_new_len, MYF(MY_WME)); + char* new_temp_buf= (char*) my_malloc(PSI_NOT_INSTRUMENTED, event_new_len, MYF(MY_WME)); if (!new_temp_buf) { @@ -3150,7 +3150,7 @@ int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len, char const* tblnam= m_tblnam; uchar* coltype= m_coltype; - m_memory= (uchar*) my_multi_malloc(MYF(MY_WME), + m_memory= (uchar*) my_multi_malloc(PSI_NOT_INSTRUMENTED, MYF(MY_WME), &m_dbnam, (uint) m_dblen + 1, &m_tblnam, (uint) m_tbllen + 1, &m_coltype, (uint) m_colcnt, @@ -3801,7 +3801,7 @@ bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to) { reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE); if (cache->end_of_file > SIZE_T_MAX || - !(to->str= (char*) my_malloc((to->length= (size_t)cache->end_of_file), MYF(0)))) + !(to->str= (char*) my_malloc(PSI_NOT_INSTRUMENTED, (to->length= (size_t)cache->end_of_file), MYF(0)))) { perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit()."); goto err; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index e01488abbb3..c6ccfc5a2c0 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -32,6 +32,8 @@ #include "rpl_record_old.h" #include "transaction.h" +PSI_memory_key key_memory_log_event_old; + #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // Old implementation of do_apply_event() @@ -899,7 +901,7 @@ int Delete_rows_log_event_old::do_before_row_operations(TABLE *table) if (table->s->keys > 0) { - m_memory= (uchar*) my_multi_malloc(MYF(MY_WME), + m_memory= (uchar*) my_multi_malloc(key_memory_log_event_old, MYF(MY_WME), &m_after_image, (uint) table->s->reclength, &m_key, @@ -908,7 +910,7 @@ int Delete_rows_log_event_old::do_before_row_operations(TABLE *table) } else { - m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME)); + m_after_image= (uchar*) my_malloc(key_memory_log_event_old, table->s->reclength, MYF(MY_WME)); m_memory= (uchar*)m_after_image; m_key= NULL; } @@ -997,7 +999,7 @@ int Update_rows_log_event_old::do_before_row_operations(TABLE *table) if (table->s->keys > 0) { - m_memory= (uchar*) my_multi_malloc(MYF(MY_WME), + m_memory= (uchar*) my_multi_malloc(key_memory_log_event_old, MYF(MY_WME), &m_after_image, (uint) table->s->reclength, &m_key, @@ -1006,7 +1008,7 @@ int Update_rows_log_event_old::do_before_row_operations(TABLE *table) } else { - m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME)); + m_after_image= (uchar*) my_malloc(key_memory_log_event_old, table->s->reclength, MYF(MY_WME)); m_memory= m_after_image; m_key= NULL; } @@ -1252,7 +1254,7 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len, m_table_id, m_flags, m_width, data_size)); DBUG_DUMP("rows_data", (uchar*) ptr_rows_data, data_size); - m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); + m_rows_buf= (uchar*) my_malloc(key_memory_log_event_old, data_size, MYF(MY_WME)); if (likely((bool)m_rows_buf)) { #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) @@ -1326,7 +1328,7 @@ int Old_rows_log_event::do_add_row_data(uchar *row_data, size_t length) my_ptrdiff_t const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); - uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc, + uchar* const new_buf= (uchar*)my_realloc(key_memory_log_event_old, (uchar*)m_rows_buf, (uint) new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME)); if (unlikely(!new_buf)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -2555,7 +2557,7 @@ Delete_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabi if (m_table->s->keys > 0) { // Allocate buffer for key searches - m_key= (uchar*)my_malloc(m_table->key_info->key_length, MYF(MY_WME)); + m_key= (uchar*)my_malloc(key_memory_log_event_old, m_table->key_info->key_length, MYF(MY_WME)); if (!m_key) return HA_ERR_OUT_OF_MEM; } @@ -2653,7 +2655,7 @@ Update_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabi if (m_table->s->keys > 0) { // Allocate buffer for key searches - m_key= (uchar*)my_malloc(m_table->key_info->key_length, MYF(MY_WME)); + m_key= (uchar*)my_malloc(key_memory_log_event_old, m_table->key_info->key_length, MYF(MY_WME)); if (!m_key) return HA_ERR_OUT_OF_MEM; } diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 202a41c2837..2267f91f0f9 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -1833,8 +1833,8 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, stmt_info_rpl.m_key, thd->db.str, thd->db.length, - thd->charset()); - THD_STAGE_INFO(thd, stage_init); + thd->charset(), NULL); + THD_STAGE_INFO(thd, stage_starting); MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length()); if (thd->m_digest != NULL) thd->m_digest->reset(thd->m_token_array, max_digest_length); @@ -3014,7 +3014,7 @@ Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg, pos_arg, (ulong) flags)); cache_type= EVENT_NO_CACHE; if (flags & DUP_NAME) - new_log_ident= my_strndup(new_log_ident_arg, ident_len, MYF(MY_WME)); + new_log_ident= my_strndup(PSI_INSTRUMENT_ME, new_log_ident_arg, ident_len, MYF(MY_WME)); if (flags & RELAY_LOG) set_relay_log_event(); DBUG_VOID_RETURN; @@ -3170,7 +3170,7 @@ Binlog_checkpoint_log_event::Binlog_checkpoint_log_event( const char *binlog_file_name_arg, uint binlog_file_len_arg) :Log_event(), - binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg, + binlog_file_name(my_strndup(PSI_INSTRUMENT_ME, binlog_file_name_arg, binlog_file_len_arg, MYF(MY_WME))), binlog_file_len(binlog_file_len_arg) { @@ -3443,8 +3443,8 @@ Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set, cache_type= EVENT_NO_CACHE; /* Failure to allocate memory will be caught by is_valid() returning false. */ if (count < (1<<28) && - (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0), - MYF(MY_WME)))) + (list = (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + count * sizeof(*list) + (count == 0), MYF(MY_WME)))) gtid_set->get_gtid_list(list, count); } @@ -3456,8 +3456,8 @@ Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set, cache_type= EVENT_NO_CACHE; /* Failure to allocate memory will be caught by is_valid() returning false. */ if (count < (1<<28) && - (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0), - MYF(MY_WME)))) + (list = (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + count * sizeof(*list) + (count == 0), MYF(MY_WME)))) { gtid_set->get_gtid_list(list, count); #if defined(HAVE_REPLICATION) @@ -3465,8 +3465,8 @@ Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set, { uint32 i; - if (!(sub_id_list= (uint64 *)my_malloc(count * sizeof(uint64), - MYF(MY_WME)))) + if (!(sub_id_list= (uint64 *)my_malloc(PSI_INSTRUMENT_ME, + count * sizeof(uint64), MYF(MY_WME)))) { my_free(list); list= NULL; @@ -4691,7 +4691,7 @@ int Execute_load_log_event::do_apply_event(rpl_group_info *rgi) don't want to overwrite it with the filename. What we want instead is add the filename to the current error message. */ - char *tmp= my_strdup(rli->last_error().message, MYF(MY_WME)); + char *tmp= my_strdup(PSI_INSTRUMENT_ME, rli->last_error().message, MYF(MY_WME)); if (tmp) { rli->report(ERROR_LEVEL, rli->last_error().number, rgi->gtid_info(), @@ -4823,8 +4823,8 @@ Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi) int error; Relay_log_info const *rli= rgi->rli; - buf= (char*) my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) + - (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME)); + buf= (char*) my_malloc(PSI_INSTRUMENT_ME, q_len + 1 - + (fn_pos_end - fn_pos_start) + (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME)); DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", my_free(buf); buf= NULL;); @@ -5036,8 +5036,8 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) size_t const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); - uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, new_alloc, - MYF(MY_ALLOW_ZERO_PTR|MY_WME)); + uchar* const new_buf= (uchar*)my_realloc(PSI_INSTRUMENT_ME, m_rows_buf, + new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME)); if (unlikely(!new_buf)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -5990,7 +5990,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, m_flags|= TM_BIT_HAS_TRIGGERS_F; /* If malloc fails, caught in is_valid() */ - if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME)))) + if ((m_memory= (uchar*) my_malloc(PSI_INSTRUMENT_ME, m_colcnt, MYF(MY_WME)))) { m_coltype= reinterpret_cast<uchar*>(m_memory); for (unsigned int i= 0 ; i < m_table->s->fields ; ++i) @@ -6006,7 +6006,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, */ uint num_null_bytes= (m_table->s->fields + 7) / 8; m_data_size+= num_null_bytes; - m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), + m_meta_memory= (uchar *)my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &m_null_bits, num_null_bytes, &m_field_metadata, (m_colcnt * 2), NULL); @@ -6158,7 +6158,7 @@ int Table_map_log_event::do_apply_event(rpl_group_info *rgi) /* Step the query id to mark what columns that are actually used. */ thd->set_query_id(next_query_id()); - if (!(memory= my_multi_malloc(MYF(MY_WME), + if (!(memory= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &table_list, (uint) sizeof(RPL_TABLE_LIST), &db_mem, (uint) NAME_LEN + 1, &tname_mem, (uint) NAME_LEN + 1, @@ -6809,7 +6809,7 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY); } - if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers ) + if (m_table->triggers && do_invoke_trigger()) m_table->prepare_triggers_for_insert_stmt_or_event(); /* Honor next number column if present */ @@ -6989,8 +6989,7 @@ Rows_log_event::write_row(rpl_group_info *rgi, TABLE *table= m_table; // pointer to event's table int error; int UNINIT_VAR(keynum); - const bool invoke_triggers= - slave_run_triggers_for_rbr && !master_had_triggers && table->triggers; + const bool invoke_triggers= (m_table->triggers && do_invoke_trigger()); auto_afree_ptr<char> key(NULL); prepare_record(table, m_width, true); @@ -7439,7 +7438,7 @@ int Rows_log_event::find_key() } // Allocate buffer for key searches - m_key= (uchar *) my_malloc(best_key->key_length, MYF(MY_WME)); + m_key= (uchar *) my_malloc(PSI_INSTRUMENT_ME, best_key->key_length, MYF(MY_WME)); if (m_key == NULL) DBUG_RETURN(HA_ERR_OUT_OF_MEM); m_key_info= best_key; @@ -7866,7 +7865,7 @@ Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability */ return 0; } - if (slave_run_triggers_for_rbr && !master_had_triggers) + if (do_invoke_trigger()) m_table->prepare_triggers_for_delete_stmt_or_event(); return find_key(); @@ -7889,8 +7888,7 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) int error; const char *tmp= thd->get_proc_info(); const char *message= "Delete_rows_log_event::find_row()"; - const bool invoke_triggers= - slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; + const bool invoke_triggers= (m_table->triggers && do_invoke_trigger()); DBUG_ASSERT(m_table != NULL); #ifdef WSREP_PROC_INFO @@ -8016,7 +8014,7 @@ Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability if ((err= find_key())) return err; - if (slave_run_triggers_for_rbr && !master_had_triggers) + if (do_invoke_trigger()) m_table->prepare_triggers_for_update_stmt_or_event(); return 0; @@ -8035,11 +8033,10 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability return error; } -int +int Update_rows_log_event::do_exec_row(rpl_group_info *rgi) { - const bool invoke_triggers= - slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; + const bool invoke_triggers= (m_table->triggers && do_invoke_trigger()); const char *tmp= thd->get_proc_info(); const char *message= "Update_rows_log_event::find_row()"; DBUG_ASSERT(m_table != NULL); diff --git a/sql/mdl.cc b/sql/mdl.cc index c4d6f89644b..5f229f73b2f 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -25,6 +25,10 @@ #include <mysql/service_thd_wait.h> #include <mysql/psi/mysql_stage.h> #include <tpool.h> +#include <pfs_metadata_provider.h> +#include <mysql/psi/mysql_mdl.h> + +static PSI_memory_key key_memory_MDL_context_acquire_locks; #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -50,6 +54,11 @@ static PSI_cond_info all_mdl_conds[]= { &key_MDL_wait_COND_wait_status, "MDL_context::COND_wait_status", 0} }; +static PSI_memory_info all_mdl_memory[]= +{ + { &key_memory_MDL_context_acquire_locks, "MDL_context::acquire_locks", 0} +}; + /** Initialise all the performance schema instrumentation points used by the MDL subsystem. @@ -67,6 +76,9 @@ static void init_mdl_psi_keys(void) count= array_elements(all_mdl_conds); mysql_cond_register("sql", all_mdl_conds, count); + count= array_elements(all_mdl_memory); + mysql_memory_register("sql", all_mdl_memory, count); + MDL_key::init_psi_keys(); } #endif /* HAVE_PSI_INTERFACE */ @@ -955,16 +967,20 @@ bool MDL_context::fix_pins() @param mdl_type The MDL lock type for the request. */ -void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace, +void MDL_request::init_with_source(MDL_key::enum_mdl_namespace mdl_namespace, const char *db_arg, const char *name_arg, enum_mdl_type mdl_type_arg, - enum_mdl_duration mdl_duration_arg) + enum_mdl_duration mdl_duration_arg, + const char *src_file, + uint src_line) { key.mdl_key_init(mdl_namespace, db_arg, name_arg); type= mdl_type_arg; duration= mdl_duration_arg; ticket= NULL; + m_src_file= src_file; + m_src_line= src_line; } @@ -977,14 +993,18 @@ void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace, @param mdl_type_arg The MDL lock type for the request. */ -void MDL_request::init(const MDL_key *key_arg, +void MDL_request::init_by_key_with_source(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, - enum_mdl_duration mdl_duration_arg) + enum_mdl_duration mdl_duration_arg, + const char *src_file, + uint src_line) { key.mdl_key_init(key_arg); type= mdl_type_arg; duration= mdl_duration_arg; ticket= NULL; + m_src_file= src_file; + m_src_line= src_line; } @@ -1013,6 +1033,9 @@ MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg void MDL_ticket::destroy(MDL_ticket *ticket) { + mysql_mdl_destroy(ticket->m_psi); + ticket->m_psi= NULL; + delete ticket; } @@ -2099,6 +2122,15 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, return TRUE; } + DBUG_ASSERT(ticket->m_psi == NULL); + ticket->m_psi= mysql_mdl_create(ticket, + &mdl_request->key, + mdl_request->type, + mdl_request->duration, + MDL_ticket::PENDING, + mdl_request->m_src_file, + mdl_request->m_src_line); + ticket->m_lock= lock; if (lock->can_grant_lock(mdl_request->type, this, false)) @@ -2110,6 +2142,8 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, m_tickets[mdl_request->duration].push_front(ticket); mdl_request->ticket= ticket; + + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); } else *out_ticket= ticket; @@ -2159,6 +2193,15 @@ MDL_context::clone_ticket(MDL_request *mdl_request) ))) return TRUE; + DBUG_ASSERT(ticket->m_psi == NULL); + ticket->m_psi= mysql_mdl_create(ticket, + &mdl_request->key, + mdl_request->type, + mdl_request->duration, + MDL_ticket::PENDING, + mdl_request->m_src_file, + mdl_request->m_src_line); + /* clone() is not supposed to be used to get a stronger lock. */ DBUG_ASSERT(mdl_request->ticket->has_stronger_or_equal_type(ticket->m_type)); @@ -2171,6 +2214,8 @@ MDL_context::clone_ticket(MDL_request *mdl_request) m_tickets[mdl_request->duration].push_front(ticket); + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + return FALSE; } @@ -2310,6 +2355,12 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) mysql_prlock_unlock(&lock->m_rwlock); + PSI_metadata_locker_state state __attribute__((unused)); + PSI_metadata_locker *locker= NULL; + + if (ticket->m_psi != NULL) + locker= PSI_CALL_start_metadata_wait(&state, ticket->m_psi, __FILE__, __LINE__); + will_wait_for(ticket); /* There is a shared or exclusive lock on the object. */ @@ -2355,6 +2406,9 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) done_waiting_for(); + if (locker != NULL) + PSI_CALL_end_metadata_wait(locker, 0); + if (wait_status != MDL_wait::GRANTED) { lock->remove_ticket(m_pins, &MDL_lock::m_waiting, ticket); @@ -2390,6 +2444,8 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) mdl_request->ticket= ticket; + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + DBUG_RETURN(FALSE); } @@ -2435,8 +2491,8 @@ bool MDL_context::acquire_locks(MDL_request_list *mdl_requests, DBUG_RETURN(FALSE); /* Sort requests according to MDL_key. */ - if (! (sort_buf= (MDL_request **)my_malloc(req_count * - sizeof(MDL_request*), + if (! (sort_buf= (MDL_request **)my_malloc(key_memory_MDL_context_acquire_locks, + req_count * sizeof(MDL_request*), MYF(MY_WME)))) DBUG_RETURN(TRUE); @@ -2521,8 +2577,8 @@ MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket, mdl_ticket->get_key()->mdl_namespace() != MDL_key::BACKUP) DBUG_RETURN(FALSE); - mdl_xlock_request.init(&mdl_ticket->m_lock->key, new_type, - MDL_TRANSACTION); + MDL_REQUEST_INIT_BY_KEY(&mdl_xlock_request, &mdl_ticket->m_lock->key, + new_type, MDL_TRANSACTION); if (acquire_lock(&mdl_xlock_request, lock_wait_timeout)) DBUG_RETURN(TRUE); @@ -2962,7 +3018,8 @@ MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace, MDL_request mdl_request; enum_mdl_duration not_unused; /* We don't care about exact duration of lock here. */ - mdl_request.init(mdl_namespace, db, name, mdl_type, MDL_TRANSACTION); + MDL_REQUEST_INIT(&mdl_request, mdl_namespace, db, name, mdl_type, + MDL_TRANSACTION); MDL_ticket *ticket= find_ticket(&mdl_request, ¬_unused); DBUG_ASSERT(ticket == NULL || ticket->m_lock); diff --git a/sql/mdl.h b/sql/mdl.h index b084670e5c6..4659238e9f2 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -353,7 +353,7 @@ enum enum_mdl_duration { or "name". */ -class MDL_key +struct MDL_key { public: #ifdef HAVE_PSI_INTERFACE @@ -535,18 +535,23 @@ public: /** A lock is requested based on a fully qualified name and type. */ MDL_key key; + const char *m_src_file; + uint m_src_line; + public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void operator delete(void *, MEM_ROOT *) {} - void init(MDL_key::enum_mdl_namespace namespace_arg, + void init_with_source(MDL_key::enum_mdl_namespace namespace_arg, const char *db_arg, const char *name_arg, enum_mdl_type mdl_type_arg, - enum_mdl_duration mdl_duration_arg); - void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, - enum_mdl_duration mdl_duration_arg); + enum_mdl_duration mdl_duration_arg, + const char *src_file, uint src_line); + void init_by_key_with_source(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, + enum_mdl_duration mdl_duration_arg, + const char *src_file, uint src_line); /** Set type of lock request. Can be only applied to pending locks. */ inline void set_type(enum_mdl_type type_arg) { @@ -610,6 +615,12 @@ public: typedef void (*mdl_cached_object_release_hook)(void *); +#define MDL_REQUEST_INIT(R, P1, P2, P3, P4, P5) \ + (*R).init_with_source(P1, P2, P3, P4, P5, __FILE__, __LINE__) + +#define MDL_REQUEST_INIT_BY_KEY(R, P1, P2, P3) \ + (*R).init_by_key_with_source(P1, P2, P3, __FILE__, __LINE__) + /** An abstract class for inspection of a connected @@ -718,6 +729,11 @@ public: /** Implement MDL_wait_for_subgraph interface. */ virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor); virtual uint get_deadlock_weight() const; + /** + Status of lock request represented by the ticket as reflected in P_S. + */ + enum enum_psi_status { PENDING = 0, GRANTED, + PRE_ACQUIRE_NOTIFY, POST_RELEASE_NOTIFY }; private: friend class MDL_context; @@ -731,9 +747,15 @@ private: m_duration(duration_arg), #endif m_ctx(ctx_arg), - m_lock(NULL) + m_lock(NULL), + m_psi(NULL) {} + virtual ~MDL_ticket() + { + DBUG_ASSERT(m_psi == NULL); + } + static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg #ifndef DBUG_OFF , enum_mdl_duration duration_arg @@ -760,6 +782,8 @@ private: */ MDL_lock *m_lock; + PSI_metadata_lock *m_psi; + private: MDL_ticket(const MDL_ticket &); /* not implemented */ MDL_ticket &operator=(const MDL_ticket &); /* not implemented */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7aa6d9bfb38..8f1c11a6518 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -113,6 +113,7 @@ #include "sp_rcontext.h" #include "sp_cache.h" #include "sql_reload.h" // reload_acl_and_cache +#include "sp_head.h" // init_sp_psi_keys #ifdef HAVE_POLL_H #include <poll.h> @@ -321,10 +322,6 @@ static PSI_rwlock_key key_rwlock_openssl; #endif #endif /* HAVE_PSI_INTERFACE */ -#ifdef HAVE_NPTL -volatile sig_atomic_t ld_assume_kernel_is_set= 0; -#endif - /** Statement instrumentation key for replication. */ @@ -789,8 +786,8 @@ static struct my_option pfs_early_options[]= {"performance_schema_consumer_events_statements_current", 0, "Default startup value for the events_statements_current consumer.", &pfs_param.m_consumer_events_statements_current_enabled, - &pfs_param.m_consumer_events_statements_current_enabled, 0, - GET_BOOL, OPT_ARG, TRUE, 0, 0, 0, 0, 0}, + &pfs_param.m_consumer_events_statements_current_enabled, 0, GET_BOOL, + OPT_ARG, FALSE, 0, 0, 0, 0, 0}, {"performance_schema_consumer_events_statements_history", 0, "Default startup value for the events_statements_history consumer.", &pfs_param.m_consumer_events_statements_history_enabled, @@ -801,6 +798,21 @@ static struct my_option pfs_early_options[]= &pfs_param.m_consumer_events_statements_history_long_enabled, &pfs_param.m_consumer_events_statements_history_long_enabled, 0, GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_transactions_current", 0, + "Default startup value for the events_transactions_current consumer.", + &pfs_param.m_consumer_events_transactions_current_enabled, + &pfs_param.m_consumer_events_transactions_current_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_transactions_history", 0, + "Default startup value for the events_transactions_history consumer.", + &pfs_param.m_consumer_events_transactions_history_enabled, + &pfs_param.m_consumer_events_transactions_history_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_transactions_history_long", 0, + "Default startup value for the events_transactions_history_long consumer.", + &pfs_param.m_consumer_events_transactions_history_long_enabled, + &pfs_param.m_consumer_events_transactions_history_long_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, {"performance_schema_consumer_events_waits_current", 0, "Default startup value for the events_waits_current consumer.", &pfs_param.m_consumer_events_waits_current_enabled, @@ -838,6 +850,19 @@ static struct my_option pfs_early_options[]= NO_ARG, 1, 0, 1, 0, 0, 0} }; +PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index, + key_file_binlog_index_cache, key_file_casetest, + key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, + key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, + key_file_loadfile, key_file_log_event_data, key_file_log_event_info, + key_file_master_info, key_file_misc, key_file_partition_ddl_log, + key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, + key_file_trg, key_file_trn, key_file_init; +PSI_file_key key_file_query_log, key_file_slow_log; +PSI_file_key key_file_relaylog, key_file_relaylog_index, + key_file_relaylog_cache, key_file_relaylog_index_cache; +PSI_file_key key_file_binlog_state; + #ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, @@ -1110,17 +1135,6 @@ static PSI_thread_info all_server_threads[]= PSI_file_key key_file_map; #endif /* HAVE_MMAP */ -PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, - key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, - key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, - key_file_loadfile, key_file_log_event_data, key_file_log_event_info, - key_file_master_info, key_file_misc, key_file_partition, - key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, - key_file_trg, key_file_trn, key_file_init; -PSI_file_key key_file_query_log, key_file_slow_log; -PSI_file_key key_file_relaylog, key_file_relaylog_index; -PSI_file_key key_file_binlog_state; - #endif /* HAVE_PSI_INTERFACE */ #ifdef HAVE_PSI_STATEMENT_INTERFACE @@ -1168,9 +1182,9 @@ void net_after_header_psi(struct st_net *net, void *user_data, thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, stmt_info_new_packet.m_key, thd->get_db(), thd->db.length, - thd->charset()); + thd->charset(), NULL); - THD_STAGE_INFO(thd, stage_init); + THD_STAGE_INFO(thd, stage_starting); } /* @@ -1296,7 +1310,7 @@ private: void Buffered_logs::init() { - init_alloc_root(&m_root, "Buffered_logs", 1024, 0, MYF(0)); + init_alloc_root(PSI_NOT_INSTRUMENTED, &m_root, 1024, 0, MYF(0)); } void Buffered_logs::cleanup() @@ -1676,7 +1690,7 @@ void kill_mysql(THD *thd) make_user_name(thd, user_host_buff); - if ((user= my_strdup(user_host_buff, MYF(0))) && + if ((user= my_strdup(PSI_NOT_INSTRUMENTED, user_host_buff, MYF(0))) && !shutdown_user.compare_exchange_strong(expected_shutdown_user, user, std::memory_order_relaxed, @@ -2953,8 +2967,7 @@ void init_signals(void) sa.sa_flags = 0; sa.sa_handler = print_signal_warning; sigaction(SIGHUP, &sa, (struct sigaction*) 0); - if (thd_lib_detected != THD_LIB_LT) - sigaddset(&set,THR_SERVER_ALARM); + sigaddset(&set,THR_SERVER_ALARM); if (test_flags & TEST_SIGINT) { /* Allow SIGINT to break mysqld. This is for debugging with --gdb */ @@ -3211,10 +3224,18 @@ extern "C" void *my_str_malloc_mysqld(size_t size); void *my_str_malloc_mysqld(size_t size) { - return my_malloc(size, MYF(MY_FAE)); + return my_malloc(key_memory_my_str_malloc, size, MYF(MY_FAE)); } +#if 0 +extern "C" void *my_str_realloc_mysqld(void *ptr, size_t size); +void *my_str_realloc_mysqld(void *ptr, size_t size) +{ + return my_realloc(key_memory_my_str_malloc, ptr, size, MYF(MY_FAE)); +} +#endif + #include <mysqld_default_groups.h> #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) @@ -3423,7 +3444,7 @@ SHOW_VAR com_status_vars[]= { {"show_generic", STMT_STATUS(SQLCOM_SHOW_GENERIC)}, {"show_grants", STMT_STATUS(SQLCOM_SHOW_GRANTS)}, {"show_keys", STMT_STATUS(SQLCOM_SHOW_KEYS)}, - {"show_master_status", STMT_STATUS(SQLCOM_SHOW_MASTER_STAT)}, + {"show_binlog_status", STMT_STATUS(SQLCOM_SHOW_BINLOG_STAT)}, {"show_open_tables", STMT_STATUS(SQLCOM_SHOW_OPEN_TABLES)}, {"show_package_status", STMT_STATUS(SQLCOM_SHOW_STATUS_PACKAGE)}, #ifndef DBUG_OFF @@ -3637,10 +3658,8 @@ int json_unescape_json(const char *json_str, const char *json_end, @returns Pointer to string containing the full file path, or NULL if it was not possible to create the path. */ -static inline const char * -rpl_make_log_name(const char *opt, - const char *def, - const char *ext) +static const char *rpl_make_log_name(PSI_memory_key key, const char *opt, + const char *def, const char *ext) { DBUG_ENTER("rpl_make_log_name"); DBUG_PRINT("enter", ("opt: %s, def: %s, ext: %s", opt, def, ext)); @@ -3658,7 +3677,7 @@ rpl_make_log_name(const char *opt, mysql_real_data_home_ptr= mysql_real_data_home; if (fn_format(buff, base, mysql_real_data_home_ptr, ext, options)) - DBUG_RETURN(my_strdup(buff, MYF(MY_WME))); + DBUG_RETURN(my_strdup(key, buff, MYF(MY_WME))); else DBUG_RETURN(NULL); } @@ -3794,7 +3813,9 @@ static int init_common_variables() key_BINLOG_COND_relay_log_updated, key_BINLOG_COND_bin_log_updated, key_file_binlog, + key_file_binlog_cache, key_file_binlog_index, + key_file_binlog_index_cache, key_BINLOG_COND_queue_busy, key_LOCK_binlog_end_pos); #endif @@ -4981,10 +5002,12 @@ static int init_server_components() } log_bin_basename= - rpl_make_log_name(opt_bin_logname, pidfile_name, + rpl_make_log_name(key_memory_MYSQL_BIN_LOG_basename, + opt_bin_logname, pidfile_name, opt_bin_logname ? "" : "-bin"); log_bin_index= - rpl_make_log_name(opt_binlog_index_name, log_bin_basename, ".index"); + rpl_make_log_name(key_memory_MYSQL_BIN_LOG_index, + opt_binlog_index_name, log_bin_basename, ".index"); if (log_bin_basename == NULL || log_bin_index == NULL) { sql_print_error("Unable to create replication path names:" @@ -5002,10 +5025,12 @@ static int init_server_components() if (opt_relay_logname) { relay_log_basename= - rpl_make_log_name(opt_relay_logname, pidfile_name, + rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_basename, + opt_relay_logname, pidfile_name, opt_relay_logname ? "" : "-relay-bin"); relay_log_index= - rpl_make_log_name(opt_relaylog_index_name, relay_log_basename, ".index"); + rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_index, + opt_relaylog_index_name, relay_log_basename, ".index"); if (relay_log_basename == NULL || relay_log_index == NULL) { sql_print_error("Unable to create replication path names:" @@ -5351,10 +5376,10 @@ int mysqld_main(int argc, char **argv) if (init_early_variables()) exit(1); -#ifdef HAVE_NPTL - ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0); -#endif #ifndef _WIN32 +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + pre_initialize_performance_schema(); +#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */ // For windows, my_init() is called from the win specific mysqld_main if (my_init()) // init my_sys library & pthreads { @@ -5454,6 +5479,7 @@ int mysqld_main(int argc, char **argv) init_server_psi_keys(); /* Instrument the main thread */ PSI_thread *psi= PSI_CALL_new_thread(key_thread_main, NULL, 0); + PSI_CALL_set_thread_os_id(psi); PSI_CALL_set_thread(psi); /* @@ -5733,7 +5759,7 @@ int mysqld_main(int argc, char **argv) mysql_cond_broadcast(&COND_server_started); mysql_mutex_unlock(&LOCK_server_started); - MYSQL_SET_STAGE(0 ,__FILE__, __LINE__); + (void)MYSQL_SET_STAGE(0 ,__FILE__, __LINE__); /* Memory used when everything is setup */ start_memory_used= global_status_var.global_memory_used; @@ -5918,6 +5944,10 @@ int mysqld_main(int argc, char **argv) /* Must be initialized early for comparison of service name */ system_charset_info= &my_charset_utf8mb3_general_ci; +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + pre_initialize_performance_schema(); +#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */ + if (my_init()) { fprintf(stderr, "my_init() failed."); @@ -6381,7 +6411,8 @@ int handle_early_options() my_getopt_skip_unknown= TRUE; /* prepare all_early_options array */ - my_init_dynamic_array(&all_early_options, sizeof(my_option), 100, 25, MYF(0)); + my_init_dynamic_array(PSI_NOT_INSTRUMENTED, &all_early_options, + sizeof(my_option), 100, 25, MYF(0)); add_many_options(&all_early_options, pfs_early_options, array_elements(pfs_early_options)); sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY); @@ -7700,7 +7731,7 @@ static int option_cmp(my_option *a, my_option *b) static void print_help() { MEM_ROOT mem_root; - init_alloc_root(&mem_root, "help", 4096, 4096, MYF(0)); + init_alloc_root(PSI_NOT_INSTRUMENTED, &mem_root, 4096, 4096, MYF(0)); pop_dynamic(&all_options); add_many_options(&all_options, pfs_early_options, @@ -8555,7 +8586,7 @@ static int get_options(int *argc_ptr, char ***argv_ptr) my_getopt_error_reporter= option_error_reporter; /* prepare all_options array */ - my_init_dynamic_array(&all_options, sizeof(my_option), + my_init_dynamic_array(PSI_INSTRUMENT_ME, &all_options, sizeof(my_option), array_elements(my_long_options) + sys_var_elements(), array_elements(my_long_options)/4, MYF(0)); add_many_options(&all_options, my_long_options, array_elements(my_long_options)); @@ -8987,7 +9018,7 @@ static int fix_paths(void) sql_print_warning("Failed to normalize the argument for --secure-file-priv."); DBUG_RETURN(1); } - char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); + char *secure_file_real_path= (char *)my_malloc(PSI_INSTRUMENT_ME, FN_REFLEN, MYF(MY_FAE)); convert_dirname(secure_file_real_path, buff, NullS); my_free(opt_secure_file_priv); opt_secure_file_priv= secure_file_real_path; @@ -9088,6 +9119,11 @@ void refresh_status(THD *thd) { mysql_mutex_lock(&LOCK_status); +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + /* Reset aggregated status counters. */ + reset_pfs_status_stats(); +#endif + /* Add thread's status variabes to global status */ add_to_status(&global_status_var, &thd->status_var); @@ -9125,9 +9161,14 @@ static PSI_file_info all_server_files[]= { &key_file_map, "map", 0}, #endif /* HAVE_MMAP */ { &key_file_binlog, "binlog", 0}, + { &key_file_binlog_cache, "binlog_cache", 0}, { &key_file_binlog_index, "binlog_index", 0}, + { &key_file_binlog_index_cache, "binlog_index_cache", 0}, { &key_file_relaylog, "relaylog", 0}, + { &key_file_relaylog_cache, "relaylog_cache", 0}, { &key_file_relaylog_index, "relaylog_index", 0}, + { &key_file_relaylog_index_cache, "relaylog_index_cache", 0}, + { &key_file_io_cache, "io_cache", 0}, { &key_file_casetest, "casetest", 0}, { &key_file_dbopt, "dbopt", 0}, { &key_file_des_key_file, "des_key_file", 0}, @@ -9142,7 +9183,7 @@ static PSI_file_info all_server_files[]= { &key_file_log_event_info, "log_event_info", 0}, { &key_file_master_info, "master_info", 0}, { &key_file_misc, "misc", 0}, - { &key_file_partition, "partition", 0}, + { &key_file_partition_ddl_log, "partition_ddl_log", 0}, { &key_file_pid, "pid", 0}, { &key_file_query_log, "query_log", 0}, { &key_file_relay_log_info, "relay_log_info", 0}, @@ -9161,25 +9202,25 @@ PSI_stage_info stage_after_create= { 0, "After create", 0}; PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0}; PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0}; PSI_stage_info stage_allocating_local_table= { 0, "Allocating local table", 0}; -PSI_stage_info stage_alter_inplace_prepare= { 0, "Preparing for alter table", 0}; -PSI_stage_info stage_alter_inplace= { 0, "Altering table", 0}; +PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0}; +PSI_stage_info stage_alter_inplace= { 0, "altering table", 0}; PSI_stage_info stage_alter_inplace_commit= { 0, "Committing alter table to storage engine", 0}; PSI_stage_info stage_apply_event= { 0, "Apply log event", 0}; PSI_stage_info stage_changing_master= { 0, "Changing master", 0}; PSI_stage_info stage_checking_master_version= { 0, "Checking master version", 0}; -PSI_stage_info stage_checking_permissions= { 0, "Checking permissions", 0}; -PSI_stage_info stage_checking_privileges_on_cached_query= { 0, "Checking privileges on cached query", 0}; +PSI_stage_info stage_checking_permissions= { 0, "checking permissions", 0}; +PSI_stage_info stage_checking_privileges_on_cached_query= { 0, "checking privileges on cached query", 0}; PSI_stage_info stage_checking_query_cache_for_query= { 0, "Checking query cache for query", 0}; PSI_stage_info stage_cleaning_up= { 0, "Reset for next command", 0}; -PSI_stage_info stage_closing_tables= { 0, "Closing tables", 0}; +PSI_stage_info stage_closing_tables= { 0, "closing tables", 0}; PSI_stage_info stage_connecting_to_master= { 0, "Connecting to master", 0}; PSI_stage_info stage_converting_heap_to_myisam= { 0, "Converting HEAP to " TMP_ENGINE_NAME, 0}; PSI_stage_info stage_copying_to_group_table= { 0, "Copying to group table", 0}; PSI_stage_info stage_copying_to_tmp_table= { 0, "Copying to tmp table", 0}; -PSI_stage_info stage_copy_to_tmp_table= { 0, "Copy to tmp table", 0}; +PSI_stage_info stage_copy_to_tmp_table= { 0, "copy to tmp table", PSI_FLAG_STAGE_PROGRESS}; PSI_stage_info stage_creating_delayed_handler= { 0, "Creating delayed handler", 0}; PSI_stage_info stage_creating_sort_index= { 0, "Creating sort index", 0}; -PSI_stage_info stage_creating_table= { 0, "Creating table", 0}; +PSI_stage_info stage_creating_table= { 0, "creating table", 0}; PSI_stage_info stage_creating_tmp_table= { 0, "Creating tmp table", 0}; PSI_stage_info stage_deleting_from_main_table= { 0, "Deleting from main table", 0}; PSI_stage_info stage_deleting_from_reference_tables= { 0, "Deleting from reference tables", 0}; @@ -9197,17 +9238,17 @@ PSI_stage_info stage_freeing_items= { 0, "Freeing items", 0}; PSI_stage_info stage_fulltext_initialization= { 0, "Fulltext initialization", 0}; PSI_stage_info stage_got_handler_lock= { 0, "Got handler lock", 0}; PSI_stage_info stage_got_old_table= { 0, "Got old table", 0}; -PSI_stage_info stage_init= { 0, "Init", 0}; -PSI_stage_info stage_init_update= { 0, "Init for update", 0}; +PSI_stage_info stage_init= { 0, "init", 0}; +PSI_stage_info stage_init_update= { 0, "init for update", 0}; PSI_stage_info stage_insert= { 0, "Insert", 0}; PSI_stage_info stage_invalidating_query_cache_entries_table= { 0, "Invalidating query cache entries (table)", 0}; PSI_stage_info stage_invalidating_query_cache_entries_table_list= { 0, "Invalidating query cache entries (table list)", 0}; PSI_stage_info stage_killing_slave= { 0, "Killing slave", 0}; PSI_stage_info stage_logging_slow_query= { 0, "Logging slow query", 0}; -PSI_stage_info stage_making_temp_file_append_before_load_data= { 0, "Making temporary file (append) before replaying LOAD DATA INFILE.", 0}; -PSI_stage_info stage_making_temp_file_create_before_load_data= { 0, "Making temporary file (create) before replaying LOAD DATA INFILE.", 0}; +PSI_stage_info stage_making_temp_file_append_before_load_data= { 0, "Making temporary file (append) before replaying LOAD DATA INFILE", 0}; +PSI_stage_info stage_making_temp_file_create_before_load_data= { 0, "Making temporary file (create) before replaying LOAD DATA INFILE", 0}; PSI_stage_info stage_manage_keys= { 0, "Manage keys", 0}; -PSI_stage_info stage_master_has_sent_all_binlog_to_slave= { 0, "Master has sent all binlog to slave; waiting for binlog to be updated", 0}; +PSI_stage_info stage_master_has_sent_all_binlog_to_slave= { 0, "Master has sent all binlog to slave; waiting for more updates", 0}; PSI_stage_info stage_opening_tables= { 0, "Opening tables", 0}; PSI_stage_info stage_optimizing= { 0, "Optimizing", 0}; PSI_stage_info stage_preparing= { 0, "Preparing", 0}; @@ -9217,7 +9258,7 @@ PSI_stage_info stage_starting_cleanup= { 0, "Starting cleanup", 0}; PSI_stage_info stage_rollback= { 0, "Rollback", 0}; PSI_stage_info stage_rollback_implicit= { 0, "Rollback_implicit", 0}; PSI_stage_info stage_commit= { 0, "Commit", 0}; -PSI_stage_info stage_commit_implicit= { 0, "Commit_implicit", 0}; +PSI_stage_info stage_commit_implicit= { 0, "Commit implicit", 0}; PSI_stage_info stage_queueing_master_event_to_the_relay_log= { 0, "Queueing master event to the relay log", 0}; PSI_stage_info stage_reading_event_from_the_relay_log= { 0, "Reading event from the relay log", 0}; PSI_stage_info stage_recreating_table= { 0, "Recreating table", 0}; @@ -9232,9 +9273,9 @@ PSI_stage_info stage_searching_rows_for_update= { 0, "Searching rows for update" PSI_stage_info stage_sending_binlog_event_to_slave= { 0, "Sending binlog event to slave", 0}; PSI_stage_info stage_sending_cached_result_to_client= { 0, "Sending cached result to client", 0}; PSI_stage_info stage_sending_data= { 0, "Sending data", 0}; -PSI_stage_info stage_setup= { 0, "Setup", 0}; +PSI_stage_info stage_setup= { 0, "setup", 0}; PSI_stage_info stage_show_explain= { 0, "Show explain", 0}; -PSI_stage_info stage_slave_has_read_all_relay_log= { 0, "Slave has read all relay log; waiting for the slave I/O thread to update it", 0}; +PSI_stage_info stage_slave_has_read_all_relay_log= { 0, "Slave has read all relay log; waiting for more updates", 0}; PSI_stage_info stage_sorting= { 0, "Sorting", 0}; PSI_stage_info stage_sorting_for_group= { 0, "Sorting for group", 0}; PSI_stage_info stage_sorting_for_order= { 0, "Sorting for order", 0}; @@ -9245,7 +9286,7 @@ PSI_stage_info stage_storing_result_in_query_cache= { 0, "Storing result in quer PSI_stage_info stage_storing_row_into_queue= { 0, "Storing row into queue", 0}; PSI_stage_info stage_system_lock= { 0, "System lock", 0}; PSI_stage_info stage_unlocking_tables= { 0, "Unlocking tables", 0}; -PSI_stage_info stage_table_lock= { 0, "Table lock", 0}; +PSI_stage_info stage_table_lock= { 0, "table lock", 0}; PSI_stage_info stage_filling_schema_table= { 0, "Filling schema table", 0}; PSI_stage_info stage_update= { 0, "Update", 0}; PSI_stage_info stage_updating= { 0, "Updating", 0}; @@ -9275,14 +9316,13 @@ PSI_stage_info stage_waiting_for_query_cache_lock= { 0, "Waiting for query cache PSI_stage_info stage_waiting_for_the_next_event_in_relay_log= { 0, "Waiting for the next event in relay log", 0}; PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position= { 0, "Waiting for the slave SQL thread to advance position", 0}; PSI_stage_info stage_waiting_to_finalize_termination= { 0, "Waiting to finalize termination", 0}; -PSI_stage_info stage_waiting_to_get_readlock= { 0, "Waiting to get readlock", 0}; PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for background binlog tasks", 0}; PSI_stage_info stage_binlog_write= { 0, "Writing to binlog", 0}; PSI_stage_info stage_binlog_processing_checkpoint_notify= { 0, "Processing binlog checkpoint notification", 0}; PSI_stage_info stage_binlog_stopping_background_thread= { 0, "Stopping binlog background thread", 0}; PSI_stage_info stage_waiting_for_work_from_sql_thread= { 0, "Waiting for work from SQL thread", 0}; PSI_stage_info stage_waiting_for_prior_transaction_to_commit= { 0, "Waiting for prior transaction to commit", 0}; -PSI_stage_info stage_waiting_for_prior_transaction_to_start_commit= { 0, "Waiting for prior transaction to start commit before starting next transaction", 0}; +PSI_stage_info stage_waiting_for_prior_transaction_to_start_commit= { 0, "Waiting for prior transaction to start commit", 0}; PSI_stage_info stage_waiting_for_room_in_worker_thread= { 0, "Waiting for room in worker thread event queue", 0}; PSI_stage_info stage_waiting_for_workers_idle= { 0, "Waiting for worker threads to be idle", 0}; PSI_stage_info stage_waiting_for_ftwrl= { 0, "Waiting due to global read lock", 0}; @@ -9290,10 +9330,92 @@ PSI_stage_info stage_waiting_for_ftwrl_threads_to_pause= { 0, "Waiting for worke PSI_stage_info stage_waiting_for_rpl_thread_pool= { 0, "Waiting while replication worker thread pool is busy", 0}; PSI_stage_info stage_master_gtid_wait_primary= { 0, "Waiting in MASTER_GTID_WAIT() (primary waiter)", 0}; PSI_stage_info stage_master_gtid_wait= { 0, "Waiting in MASTER_GTID_WAIT()", 0}; -PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process GTID received on multiple master connections", 0}; +PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process the same GTID", 0}; PSI_stage_info stage_slave_background_process_request= { 0, "Processing requests", 0}; PSI_stage_info stage_slave_background_wait_request= { 0, "Waiting for requests", 0}; PSI_stage_info stage_waiting_for_deadlock_kill= { 0, "Waiting for parallel replication deadlock handling to complete", 0}; +PSI_stage_info stage_starting= { 0, "starting", 0}; + +PSI_memory_key key_memory_DATE_TIME_FORMAT; +PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY; +PSI_memory_key key_memory_Event_queue_element_for_exec_names; +PSI_memory_key key_memory_Event_scheduler_scheduler_param; +PSI_memory_key key_memory_Filesort_info_merge; +PSI_memory_key key_memory_Filesort_info_record_pointers; +PSI_memory_key key_memory_Gis_read_stream_err_msg; +PSI_memory_key key_memory_JOIN_CACHE; +PSI_memory_key key_memory_MPVIO_EXT_auth_info; +PSI_memory_key key_memory_MYSQL_BIN_LOG_basename; +PSI_memory_key key_memory_MYSQL_BIN_LOG_index; +PSI_memory_key key_memory_MYSQL_LOCK; +PSI_memory_key key_memory_MYSQL_LOG_name; +PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename; +PSI_memory_key key_memory_MYSQL_RELAY_LOG_index; +PSI_memory_key key_memory_NAMED_ILINK_name; +PSI_memory_key key_memory_PROFILE; +PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc; +PSI_memory_key key_memory_Query_cache; +PSI_memory_key key_memory_Relay_log_info_group_relay_log_name; +PSI_memory_key key_memory_Row_data_memory_memory; +PSI_memory_key key_memory_Rpl_info_file_buffer; +PSI_memory_key key_memory_SLAVE_INFO; +PSI_memory_key key_memory_ST_SCHEMA_TABLE; +PSI_memory_key key_memory_Sort_param_tmp_buffer; +PSI_memory_key key_memory_Sys_var_charptr_value; +PSI_memory_key key_memory_TABLE; +PSI_memory_key key_memory_TABLE_RULE_ENT; +PSI_memory_key key_memory_TC_LOG_MMAP_pages; +PSI_memory_key key_memory_THD_db; +PSI_memory_key key_memory_THD_handler_tables_hash; +PSI_memory_key key_memory_THD_variables; +PSI_memory_key key_memory_Table_trigger_dispatcher; +PSI_memory_key key_memory_Unique_merge_buffer; +PSI_memory_key key_memory_Unique_sort_buffer; +PSI_memory_key key_memory_User_level_lock; +PSI_memory_key key_memory_XID; +PSI_memory_key key_memory_acl_cache; +PSI_memory_key key_memory_acl_mem; +PSI_memory_key key_memory_acl_memex; +PSI_memory_key key_memory_binlog_cache_mngr; +PSI_memory_key key_memory_binlog_pos; +PSI_memory_key key_memory_binlog_recover_exec; +PSI_memory_key key_memory_binlog_statement_buffer; +PSI_memory_key key_memory_binlog_ver_1_event; +PSI_memory_key key_memory_bison_stack; +PSI_memory_key key_memory_blob_mem_storage; +PSI_memory_key key_memory_dboptions_hash; +PSI_memory_key key_memory_errmsgs; +PSI_memory_key key_memory_frm_string; +PSI_memory_key key_memory_gdl; +PSI_memory_key key_memory_global_system_variables; +PSI_memory_key key_memory_handler_errmsgs; +PSI_memory_key key_memory_handlerton; +PSI_memory_key key_memory_hash_index_key_buffer; +PSI_memory_key key_memory_host_cache_hostname; +PSI_memory_key key_memory_ignored_db; +PSI_memory_key key_memory_locked_table_list; +PSI_memory_key key_memory_locked_thread_list; +PSI_memory_key key_memory_my_str_malloc; +PSI_memory_key key_memory_native_functions; +PSI_memory_key key_memory_prepared_statement_main_mem_root; +PSI_memory_key key_memory_prepared_statement_map; +PSI_memory_key key_memory_queue_item; +PSI_memory_key key_memory_quick_range_select_root; +PSI_memory_key key_memory_rpl_filter; +PSI_memory_key key_memory_sp_cache; +PSI_memory_key key_memory_sp_head_call_root; +PSI_memory_key key_memory_sp_head_execute_root; +PSI_memory_key key_memory_sp_head_main_root; +PSI_memory_key key_memory_table_mapping_root; +PSI_memory_key key_memory_table_share; +PSI_memory_key key_memory_table_triggers_list; +PSI_memory_key key_memory_thd_main_mem_root; +PSI_memory_key key_memory_thd_transactions; +PSI_memory_key key_memory_user_conn; +PSI_memory_key key_memory_user_var_entry; +PSI_memory_key key_memory_user_var_entry_value; + +PSI_memory_key key_memory_String_value; #ifdef HAVE_PSI_INTERFACE @@ -9422,7 +9544,6 @@ PSI_stage_info *all_server_stages[]= & stage_waiting_for_the_slave_thread_to_advance_position, & stage_waiting_for_work_from_sql_thread, & stage_waiting_to_finalize_termination, - & stage_waiting_to_get_readlock, & stage_master_gtid_wait_primary, & stage_master_gtid_wait, & stage_gtid_wait_other_connection, @@ -9431,7 +9552,8 @@ PSI_stage_info *all_server_stages[]= & stage_waiting_for_semi_sync_ack_from_slave, & stage_waiting_for_semi_sync_slave, & stage_reading_semi_sync_ack, - & stage_waiting_for_deadlock_kill + & stage_waiting_for_deadlock_kill, + & stage_starting }; PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; @@ -9443,6 +9565,145 @@ static PSI_socket_info all_server_sockets[]= { &key_socket_client_connection, "client_connection", 0} }; +static PSI_memory_info all_server_memory[]= +{ + { &key_memory_locked_table_list, "Locked_tables_list::m_locked_tables_root", 0}, + { &key_memory_locked_thread_list, "display_table_locks", PSI_FLAG_THREAD}, + { &key_memory_thd_transactions, "THD::transactions::mem_root", PSI_FLAG_THREAD}, +// { &key_memory_delegate, "Delegate::memroot", 0}, + { &key_memory_acl_mem, "sql_acl_mem", PSI_FLAG_GLOBAL}, + { &key_memory_acl_memex, "sql_acl_memex", PSI_FLAG_GLOBAL}, + { &key_memory_acl_cache, "acl_cache", PSI_FLAG_GLOBAL}, + { &key_memory_thd_main_mem_root, "thd::main_mem_root", PSI_FLAG_THREAD}, +// { &key_memory_help, "help", 0}, +// { &key_memory_new_frm_mem, "new_frm_mem", 0}, + { &key_memory_table_share, "TABLE_SHARE::mem_root", PSI_FLAG_GLOBAL}, /* table definition cache */ + { &key_memory_gdl, "gdl", 0}, + { &key_memory_table_triggers_list, "Table_triggers_list", 0}, +// { &key_memory_servers, "servers", 0}, + { &key_memory_prepared_statement_map, "Prepared_statement_map", PSI_FLAG_THREAD}, + { &key_memory_prepared_statement_main_mem_root, "Prepared_statement::main_mem_root", PSI_FLAG_THREAD}, +// { &key_memory_protocol_rset_root, "Protocol_local::m_rset_root", PSI_FLAG_THREAD}, +// { &key_memory_warning_info_warn_root, "Warning_info::m_warn_root", PSI_FLAG_THREAD}, + { &key_memory_sp_cache, "THD::sp_cache", 0}, + { &key_memory_sp_head_main_root, "sp_head::main_mem_root", 0}, + { &key_memory_sp_head_execute_root, "sp_head::execute_mem_root", PSI_FLAG_THREAD}, + { &key_memory_sp_head_call_root, "sp_head::call_mem_root", PSI_FLAG_THREAD}, + { &key_memory_table_mapping_root, "table_mapping::m_mem_root", 0}, + { &key_memory_quick_range_select_root, "QUICK_RANGE_SELECT::alloc", PSI_FLAG_THREAD}, +// { &key_memory_quick_index_merge_root, "QUICK_INDEX_MERGE_SELECT::alloc", PSI_FLAG_THREAD}, +// { &key_memory_quick_ror_intersect_select_root, "QUICK_ROR_INTERSECT_SELECT::alloc", PSI_FLAG_THREAD}, +// { &key_memory_quick_ror_union_select_root, "QUICK_ROR_UNION_SELECT::alloc", PSI_FLAG_THREAD}, +// { &key_memory_quick_group_min_max_select_root, "QUICK_GROUP_MIN_MAX_SELECT::alloc", PSI_FLAG_THREAD}, +// { &key_memory_test_quick_select_exec, "test_quick_select", PSI_FLAG_THREAD}, +// { &key_memory_prune_partitions_exec, "prune_partitions::exec", 0}, + { &key_memory_binlog_recover_exec, "MYSQL_BIN_LOG::recover", 0}, + { &key_memory_blob_mem_storage, "Blob_mem_storage::storage", 0}, + { &key_memory_NAMED_ILINK_name, "NAMED_ILINK::name", 0}, + { &key_memory_String_value, "String::value", 0}, + { &key_memory_Sys_var_charptr_value, "Sys_var_charptr::value", 0}, + { &key_memory_queue_item, "Queue::queue_item", 0}, + { &key_memory_THD_db, "THD::db", 0}, + { &key_memory_user_var_entry, "user_var_entry", 0}, +// { &key_memory_Slave_job_group_group_relay_log_name, "Slave_job_group::group_relay_log_name", 0}, + { &key_memory_Relay_log_info_group_relay_log_name, "Relay_log_info::group_relay_log_name", 0}, + { &key_memory_binlog_cache_mngr, "binlog_cache_mngr", 0}, + { &key_memory_Row_data_memory_memory, "Row_data_memory::memory", 0}, +// { &key_memory_Gtid_set_to_string, "Gtid_set::to_string", 0}, +// { &key_memory_Gtid_state_to_string, "Gtid_state::to_string", 0}, +// { &key_memory_Owned_gtids_to_string, "Owned_gtids::to_string", 0}, +// { &key_memory_log_event, "Log_event", 0}, +// { &key_memory_Incident_log_event_message, "Incident_log_event::message", 0}, +// { &key_memory_Rows_query_log_event_rows_query, "Rows_query_log_event::rows_query", 0}, + { &key_memory_Sort_param_tmp_buffer, "Sort_param::tmp_buffer", 0}, + { &key_memory_Filesort_info_merge, "Filesort_info::merge", 0}, + { &key_memory_Filesort_info_record_pointers, "Filesort_info::record_pointers", 0}, +// { &key_memory_Filesort_buffer_sort_keys, "Filesort_buffer::sort_keys", 0}, + { &key_memory_handler_errmsgs, "handler::errmsgs", 0}, + { &key_memory_handlerton, "handlerton", 0}, + { &key_memory_XID, "XID", 0}, + { &key_memory_host_cache_hostname, "host_cache::hostname", 0}, + { &key_memory_user_var_entry_value, "user_var_entry::value", 0}, + { &key_memory_User_level_lock, "User_level_lock", 0}, + { &key_memory_MYSQL_LOG_name, "MYSQL_LOG::name", 0}, + { &key_memory_TC_LOG_MMAP_pages, "TC_LOG_MMAP::pages", 0}, +// { &key_memory_my_bitmap_map, "my_bitmap_map", 0}, + { &key_memory_QUICK_RANGE_SELECT_mrr_buf_desc, "QUICK_RANGE_SELECT::mrr_buf_desc", 0}, + { &key_memory_Event_queue_element_for_exec_names, "Event_queue_element_for_exec::names", 0}, + { &key_memory_my_str_malloc, "my_str_malloc", 0}, + { &key_memory_MYSQL_BIN_LOG_basename, "MYSQL_BIN_LOG::basename", 0}, + { &key_memory_MYSQL_BIN_LOG_index, "MYSQL_BIN_LOG::index", 0}, + { &key_memory_MYSQL_RELAY_LOG_basename, "MYSQL_RELAY_LOG::basename", 0}, + { &key_memory_MYSQL_RELAY_LOG_index, "MYSQL_RELAY_LOG::index", 0}, + { &key_memory_rpl_filter, "rpl_filter memory", 0}, + { &key_memory_errmsgs, "errmsgs", 0}, + { &key_memory_Gis_read_stream_err_msg, "Gis_read_stream::err_msg", 0}, +// { &key_memory_Geometry_objects_data, "Geometry::ptr_and_wkb_data", 0}, + { &key_memory_MYSQL_LOCK, "MYSQL_LOCK", 0}, +// { &key_memory_NET_buff, "NET::buff", 0}, +// { &key_memory_NET_compress_packet, "NET::compress_packet", 0}, + { &key_memory_Event_scheduler_scheduler_param, "Event_scheduler::scheduler_param", 0}, +// { &key_memory_Gtid_set_Interval_chunk, "Gtid_set::Interval_chunk", 0}, +// { &key_memory_Owned_gtids_sidno_to_hash, "Owned_gtids::sidno_to_hash", 0}, +// { &key_memory_Sid_map_Node, "Sid_map::Node", 0}, +// { &key_memory_Gtid_state_group_commit_sidno, "Gtid_state::group_commit_sidno_locks", 0}, +// { &key_memory_Mutex_cond_array_Mutex_cond, "Mutex_cond_array::Mutex_cond", 0}, + { &key_memory_TABLE_RULE_ENT, "TABLE_RULE_ENT", 0}, +// { &key_memory_Rpl_info_table, "Rpl_info_table", 0}, + { &key_memory_Rpl_info_file_buffer, "Rpl_info_file::buffer", 0}, +// { &key_memory_db_worker_hash_entry, "db_worker_hash_entry", 0}, +// { &key_memory_rpl_slave_check_temp_dir, "rpl_slave::check_temp_dir", 0}, +// { &key_memory_rpl_slave_command_buffer, "rpl_slave::command_buffer", 0}, + { &key_memory_binlog_ver_1_event, "binlog_ver_1_event", 0}, + { &key_memory_SLAVE_INFO, "SLAVE_INFO", 0}, + { &key_memory_binlog_pos, "binlog_pos", 0}, +// { &key_memory_HASH_ROW_ENTRY, "HASH_ROW_ENTRY", 0}, + { &key_memory_binlog_statement_buffer, "binlog_statement_buffer", 0}, +// { &key_memory_partition_syntax_buffer, "partition_syntax_buffer", 0}, +// { &key_memory_READ_INFO, "READ_INFO", 0}, + { &key_memory_JOIN_CACHE, "JOIN_CACHE", 0}, +// { &key_memory_TABLE_sort_io_cache, "TABLE::sort_io_cache", 0}, +// { &key_memory_frm, "frm", 0}, + { &key_memory_Unique_sort_buffer, "Unique::sort_buffer", 0}, + { &key_memory_Unique_merge_buffer, "Unique::merge_buffer", 0}, + { &key_memory_TABLE, "TABLE", PSI_FLAG_GLOBAL}, /* Table cache */ +// { &key_memory_frm_extra_segment_buff, "frm::extra_segment_buff", 0}, +// { &key_memory_frm_form_pos, "frm::form_pos", 0}, + { &key_memory_frm_string, "frm::string", 0}, +// { &key_memory_LOG_name, "LOG_name", 0}, + { &key_memory_DATE_TIME_FORMAT, "DATE_TIME_FORMAT", 0}, + { &key_memory_DDL_LOG_MEMORY_ENTRY, "DDL_LOG_MEMORY_ENTRY", 0}, + { &key_memory_ST_SCHEMA_TABLE, "ST_SCHEMA_TABLE", 0}, + { &key_memory_ignored_db, "ignored_db", 0}, + { &key_memory_PROFILE, "PROFILE", 0}, + { &key_memory_global_system_variables, "global_system_variables", 0}, + { &key_memory_THD_variables, "THD::variables", 0}, +// { &key_memory_Security_context, "Security_context", 0}, +// { &key_memory_shared_memory_name, "Shared_memory_name", 0}, + { &key_memory_bison_stack, "bison_stack", 0}, + { &key_memory_THD_handler_tables_hash, "THD::handler_tables_hash", 0}, + { &key_memory_hash_index_key_buffer, "hash_index_key_buffer", 0}, + { &key_memory_dboptions_hash, "dboptions_hash", 0}, + { &key_memory_user_conn, "user_conn", 0}, +// { &key_memory_LOG_POS_COORD, "LOG_POS_COORD", 0}, +// { &key_memory_XID_STATE, "XID_STATE", 0}, + { &key_memory_MPVIO_EXT_auth_info, "MPVIO_EXT::auth_info", 0}, +// { &key_memory_opt_bin_logname, "opt_bin_logname", 0}, + { &key_memory_Query_cache, "Query_cache", PSI_FLAG_GLOBAL}, +// { &key_memory_READ_RECORD_cache, "READ_RECORD_cache", 0}, +// { &key_memory_Quick_ranges, "Quick_ranges", 0}, +// { &key_memory_File_query_log_name, "File_query_log::name", 0}, + { &key_memory_Table_trigger_dispatcher, "Table_trigger_dispatcher::m_mem_root", 0}, +// { &key_memory_thd_timer, "thd_timer", 0}, +// { &key_memory_THD_Session_tracker, "THD::Session_tracker", 0}, +// { &key_memory_THD_Session_sysvar_resource_manager, "THD::Session_sysvar_resource_manager", 0}, +// { &key_memory_show_slave_status_io_gtid_set, "show_slave_status_io_gtid_set", 0}, +// { &key_memory_write_set_extraction, "write_set_extraction", 0}, +// { &key_memory_get_all_tables, "get_all_tables", 0}, +// { &key_memory_fill_schema_schemata, "fill_schema_schemata", 0}, + { &key_memory_native_functions, "native_functions", PSI_FLAG_GLOBAL}, +}; + /** Initialise all the performance schema instrumentation points used by the server. @@ -9473,11 +9734,16 @@ void init_server_psi_keys(void) count= array_elements(all_server_sockets); mysql_socket_register(category, all_server_sockets, count); + count= array_elements(all_server_memory); + mysql_memory_register(category, all_server_memory, count); + #ifdef HAVE_PSI_STATEMENT_INTERFACE init_sql_statement_info(); count= array_elements(sql_statement_info); mysql_statement_register(category, sql_statement_info, count); + init_sp_psi_keys(); + category= "com"; init_com_statement_info(); diff --git a/sql/mysqld.h b/sql/mysqld.h index 7261b25cab0..018c8cdcaf5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -306,7 +306,6 @@ extern my_bool disconnect_on_expired_password; enum secure_timestamp { SECTIME_NO, SECTIME_SUPER, SECTIME_REPL, SECTIME_YES }; -#ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; @@ -391,22 +390,153 @@ extern PSI_thread_key key_thread_delayed_insert, key_thread_one_connection, key_thread_signal_hand, key_thread_slave_background, key_rpl_parallel_thread; -extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, +extern PSI_file_key key_file_binlog, key_file_binlog_cache, + key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest, key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, key_file_loadfile, key_file_log_event_data, key_file_log_event_info, - key_file_master_info, key_file_misc, key_file_partition, + key_file_master_info, key_file_misc, key_file_partition_ddl_log, key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, key_file_trg, key_file_trn, key_file_init; extern PSI_file_key key_file_query_log, key_file_slow_log; -extern PSI_file_key key_file_relaylog, key_file_relaylog_index; +extern PSI_file_key key_file_relaylog, key_file_relaylog_index, + key_file_relaylog_cache, key_file_relaylog_index_cache; extern PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; extern PSI_file_key key_file_binlog_state; +#ifdef HAVE_PSI_INTERFACE void init_server_psi_keys(); #endif /* HAVE_PSI_INTERFACE */ +extern PSI_memory_key key_memory_locked_table_list; +extern PSI_memory_key key_memory_locked_thread_list; +extern PSI_memory_key key_memory_thd_transactions; +extern PSI_memory_key key_memory_delegate; +extern PSI_memory_key key_memory_acl_mem; +extern PSI_memory_key key_memory_acl_memex; +extern PSI_memory_key key_memory_acl_cache; +extern PSI_memory_key key_memory_thd_main_mem_root; +extern PSI_memory_key key_memory_help; +extern PSI_memory_key key_memory_frm; +extern PSI_memory_key key_memory_table_share; +extern PSI_memory_key key_memory_gdl; +extern PSI_memory_key key_memory_table_triggers_list; +extern PSI_memory_key key_memory_prepared_statement_map; +extern PSI_memory_key key_memory_prepared_statement_main_mem_root; +extern PSI_memory_key key_memory_protocol_rset_root; +extern PSI_memory_key key_memory_warning_info_warn_root; +extern PSI_memory_key key_memory_sp_cache; +extern PSI_memory_key key_memory_sp_head_main_root; +extern PSI_memory_key key_memory_sp_head_execute_root; +extern PSI_memory_key key_memory_sp_head_call_root; +extern PSI_memory_key key_memory_table_mapping_root; +extern PSI_memory_key key_memory_quick_range_select_root; +extern PSI_memory_key key_memory_quick_index_merge_root; +extern PSI_memory_key key_memory_quick_ror_intersect_select_root; +extern PSI_memory_key key_memory_quick_ror_union_select_root; +extern PSI_memory_key key_memory_quick_group_min_max_select_root; +extern PSI_memory_key key_memory_test_quick_select_exec; +extern PSI_memory_key key_memory_prune_partitions_exec; +extern PSI_memory_key key_memory_binlog_recover_exec; +extern PSI_memory_key key_memory_blob_mem_storage; + +extern PSI_memory_key key_memory_Sys_var_charptr_value; +extern PSI_memory_key key_memory_THD_db; +extern PSI_memory_key key_memory_user_var_entry; +extern PSI_memory_key key_memory_user_var_entry_value; +extern PSI_memory_key key_memory_Slave_job_group_group_relay_log_name; +extern PSI_memory_key key_memory_Relay_log_info_group_relay_log_name; +extern PSI_memory_key key_memory_binlog_cache_mngr; +extern PSI_memory_key key_memory_Row_data_memory_memory; +extern PSI_memory_key key_memory_errmsgs; +extern PSI_memory_key key_memory_Event_queue_element_for_exec_names; +extern PSI_memory_key key_memory_Event_scheduler_scheduler_param; +extern PSI_memory_key key_memory_Gis_read_stream_err_msg; +extern PSI_memory_key key_memory_Geometry_objects_data; +extern PSI_memory_key key_memory_host_cache_hostname; +extern PSI_memory_key key_memory_User_level_lock; +extern PSI_memory_key key_memory_Filesort_info_record_pointers; +extern PSI_memory_key key_memory_Sort_param_tmp_buffer; +extern PSI_memory_key key_memory_Filesort_info_merge; +extern PSI_memory_key key_memory_Filesort_buffer_sort_keys; +extern PSI_memory_key key_memory_handler_errmsgs; +extern PSI_memory_key key_memory_handlerton; +extern PSI_memory_key key_memory_XID; +extern PSI_memory_key key_memory_MYSQL_LOCK; +extern PSI_memory_key key_memory_MYSQL_LOG_name; +extern PSI_memory_key key_memory_TC_LOG_MMAP_pages; +extern PSI_memory_key key_memory_my_str_malloc; +extern PSI_memory_key key_memory_MYSQL_BIN_LOG_basename; +extern PSI_memory_key key_memory_MYSQL_BIN_LOG_index; +extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename; +extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_index; +extern PSI_memory_key key_memory_rpl_filter; +extern PSI_memory_key key_memory_Security_context; +extern PSI_memory_key key_memory_NET_buff; +extern PSI_memory_key key_memory_NET_compress_packet; +extern PSI_memory_key key_memory_my_bitmap_map; +extern PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc; +extern PSI_memory_key key_memory_TABLE_RULE_ENT; +extern PSI_memory_key key_memory_Mutex_cond_array_Mutex_cond; +extern PSI_memory_key key_memory_Owned_gtids_sidno_to_hash; +extern PSI_memory_key key_memory_Sid_map_Node; +extern PSI_memory_key key_memory_bison_stack; +extern PSI_memory_key key_memory_TABLE_sort_io_cache; +extern PSI_memory_key key_memory_DATE_TIME_FORMAT; +extern PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY; +extern PSI_memory_key key_memory_ST_SCHEMA_TABLE; +extern PSI_memory_key key_memory_ignored_db; +extern PSI_memory_key key_memory_SLAVE_INFO; +extern PSI_memory_key key_memory_log_event_old; +extern PSI_memory_key key_memory_HASH_ROW_ENTRY; +extern PSI_memory_key key_memory_table_def_memory; +extern PSI_memory_key key_memory_MPVIO_EXT_auth_info; +extern PSI_memory_key key_memory_LOG_POS_COORD; +extern PSI_memory_key key_memory_XID_STATE; +extern PSI_memory_key key_memory_Rpl_info_file_buffer; +extern PSI_memory_key key_memory_Rpl_info_table; +extern PSI_memory_key key_memory_binlog_pos; +extern PSI_memory_key key_memory_db_worker_hash_entry; +extern PSI_memory_key key_memory_rpl_slave_command_buffer; +extern PSI_memory_key key_memory_binlog_ver_1_event; +extern PSI_memory_key key_memory_rpl_slave_check_temp_dir; +extern PSI_memory_key key_memory_TABLE; +extern PSI_memory_key key_memory_binlog_statement_buffer; +extern PSI_memory_key key_memory_user_conn; +extern PSI_memory_key key_memory_dboptions_hash; +extern PSI_memory_key key_memory_hash_index_key_buffer; +extern PSI_memory_key key_memory_THD_handler_tables_hash; +extern PSI_memory_key key_memory_JOIN_CACHE; +extern PSI_memory_key key_memory_READ_INFO; +extern PSI_memory_key key_memory_partition_syntax_buffer; +extern PSI_memory_key key_memory_global_system_variables; +extern PSI_memory_key key_memory_THD_variables; +extern PSI_memory_key key_memory_PROFILE; +extern PSI_memory_key key_memory_LOG_name; +extern PSI_memory_key key_memory_string_iterator; +extern PSI_memory_key key_memory_frm_extra_segment_buff; +extern PSI_memory_key key_memory_frm_form_pos; +extern PSI_memory_key key_memory_frm_string; +extern PSI_memory_key key_memory_Unique_sort_buffer; +extern PSI_memory_key key_memory_Unique_merge_buffer; +extern PSI_memory_key key_memory_shared_memory_name; +extern PSI_memory_key key_memory_opt_bin_logname; +extern PSI_memory_key key_memory_Query_cache; +extern PSI_memory_key key_memory_READ_RECORD_cache; +extern PSI_memory_key key_memory_Quick_ranges; +extern PSI_memory_key key_memory_File_query_log_name; +extern PSI_memory_key key_memory_Table_trigger_dispatcher; +extern PSI_memory_key key_memory_show_slave_status_io_gtid_set; +extern PSI_memory_key key_memory_write_set_extraction; +extern PSI_memory_key key_memory_thd_timer; +extern PSI_memory_key key_memory_THD_Session_tracker; +extern PSI_memory_key key_memory_THD_Session_sysvar_resource_manager; +extern PSI_memory_key key_memory_get_all_tables; +extern PSI_memory_key key_memory_fill_schema_schemata; +extern PSI_memory_key key_memory_native_functions; +extern PSI_memory_key key_memory_JSON; + /* MAINTAINER: Please keep this list in order, to limit merge collisions. Hint: grep PSI_stage_info | sort -u @@ -526,7 +656,6 @@ extern PSI_stage_info stage_waiting_for_table_flush; extern PSI_stage_info stage_waiting_for_the_next_event_in_relay_log; extern PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position; extern PSI_stage_info stage_waiting_to_finalize_termination; -extern PSI_stage_info stage_waiting_to_get_readlock; extern PSI_stage_info stage_binlog_waiting_background_tasks; extern PSI_stage_info stage_binlog_write; extern PSI_stage_info stage_binlog_processing_checkpoint_notify; @@ -545,6 +674,7 @@ extern PSI_stage_info stage_gtid_wait_other_connection; extern PSI_stage_info stage_slave_background_process_request; extern PSI_stage_info stage_slave_background_wait_request; extern PSI_stage_info stage_waiting_for_deadlock_kill; +extern PSI_stage_info stage_starting; #ifdef HAVE_PSI_STATEMENT_INTERFACE /** diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 4fecf8bffd0..840593cd2db 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -47,6 +47,9 @@ #include "probes_mysql.h" #include "proxy_protocol.h" +PSI_memory_key key_memory_NET_buff; +PSI_memory_key key_memory_NET_compress_packet; + #ifdef EMBEDDED_LIBRARY #undef MYSQL_SERVER #undef MYSQL_CLIENT @@ -176,8 +179,9 @@ my_bool my_net_init(NET *net, Vio *vio, void *thd, uint my_flags) my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags) { DBUG_ENTER("net_allocate_new_packet"); - if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+ - NET_HEADER_SIZE + COMP_HEADER_SIZE +1, + if (!(net->buff=(uchar*) my_malloc(key_memory_NET_buff, + (size_t) net->max_packet + + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1, MYF(MY_WME | my_flags)))) DBUG_RETURN(1); net->buff_end=net->buff+net->max_packet; @@ -221,11 +225,11 @@ my_bool net_realloc(NET *net, size_t length) my_real_read() may actually read 4 bytes depending on build flags and platform. */ - if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length + + if (!(buff= (uchar*) my_realloc(key_memory_NET_buff, + (char*) net->buff, pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1, - MYF(MY_WME | - (net->thread_specific_malloc ? - MY_THREAD_SPECIFIC : 0))))) + MYF(MY_WME | (net->thread_specific_malloc + ? MY_THREAD_SPECIFIC : 0))))) { /* @todo: 1 and 2 codes are identical. */ net->error= 1; @@ -636,11 +640,10 @@ net_real_write(NET *net,const uchar *packet, size_t len) size_t complen; uchar *b; uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE; - if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE + - COMP_HEADER_SIZE + 1, - MYF(MY_WME | - (net->thread_specific_malloc ? - MY_THREAD_SPECIFIC : 0))))) + if (!(b= (uchar*) my_malloc(key_memory_NET_compress_packet, + len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1, + MYF(MY_WME | (net->thread_specific_malloc + ? MY_THREAD_SPECIFIC : 0))))) { net->error= 2; net->last_errno= ER_OUT_OF_RESOURCES; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b4e2cfdf599..5822aaa8250 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1267,9 +1267,8 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, if (!no_alloc && !parent_alloc) { // Allocates everything through the internal memroot - init_sql_alloc(&alloc, "QUICK_RANGE_SELECT", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); thd->mem_root= &alloc; } else @@ -1277,7 +1276,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, file= head->file; record= head->record[0]; - my_init_dynamic_array2(&ranges, sizeof(QUICK_RANGE*), + my_init_dynamic_array2(PSI_INSTRUMENT_ME, &ranges, sizeof(QUICK_RANGE*), thd->alloc(sizeof(QUICK_RANGE*) * 16), 16, 16, MYF(MY_THREAD_SPECIFIC)); @@ -1363,9 +1362,8 @@ QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, TABLE *table) DBUG_ENTER("QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT"); index= MAX_KEY; head= table; - init_sql_alloc(&alloc, "QUICK_INDEX_SORT_SELECT", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); DBUG_VOID_RETURN; } @@ -1435,9 +1433,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param, head= table; record= head->record[0]; if (!parent_alloc) - init_sql_alloc(&alloc, "QUICK_ROR_INTERSECT_SELECT", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); else bzero(&alloc, sizeof(MEM_ROOT)); last_rowid= (uchar*) alloc_root(parent_alloc? parent_alloc : &alloc, @@ -1713,9 +1710,8 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, head= table; rowid_length= table->file->ref_length; record= head->record[0]; - init_sql_alloc(&alloc, "QUICK_ROR_UNION_SELECT", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); thd_param->mem_root= &alloc; } @@ -2726,9 +2722,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.possible_keys.clear_all(); thd->no_errors=1; // Don't warn about NULL - init_sql_alloc(&alloc, "test_quick_select", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc, sizeof(KEY_PART) * @@ -3407,9 +3402,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) SEL_TREE *tree; double rows; - init_sql_alloc(&alloc, "calculate_cond_selectivity_for_table", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); param.thd= thd; param.mem_root= &alloc; param.old_root= thd->mem_root; @@ -3839,9 +3833,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) my_bitmap_map *old_sets[2]; prune_param.part_info= part_info; - init_sql_alloc(&alloc, "prune_partitions", - thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); range_par->mem_root= &alloc; range_par->old_root= thd->mem_root; @@ -12098,7 +12091,8 @@ int QUICK_RANGE_SELECT::reset() if (mrr_buf_size && !mrr_buf_desc) { buf_size= mrr_buf_size; - while (buf_size && !my_multi_malloc(MYF(MY_WME), + while (buf_size && !my_multi_malloc(key_memory_QUICK_RANGE_SELECT_mrr_buf_desc, + MYF(MY_WME), &mrr_buf_desc, sizeof(*mrr_buf_desc), &mrange_buff, buf_size, NullS)) @@ -14450,10 +14444,10 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, DBUG_ASSERT(!parent_alloc); if (!parent_alloc) { - init_sql_alloc(&alloc, "QUICK_GROUP_MIN_MAX_SELECT", - join->thd->variables.range_alloc_block_size, 0, - MYF(MY_THREAD_SPECIFIC)); - join->thd->mem_root= &alloc; + THD *thd= join->thd; + init_sql_alloc(key_memory_quick_range_select_root, &alloc, + thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); + thd->mem_root= &alloc; } else bzero(&alloc, sizeof(MEM_ROOT)); // ensure that it's not used @@ -14513,7 +14507,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::init() if (min_max_arg_part) { - if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16, + if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &min_max_ranges, + sizeof(QUICK_RANGE*), 16, 16, MYF(MY_THREAD_SPECIFIC))) return 1; diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 6f8248c315c..b27a0d757cb 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -341,7 +341,7 @@ bool JOIN::check_for_splittable_materialized() return false; ORDER *ord; - Dynamic_array<SplM_field_ext_info> candidates; + Dynamic_array<SplM_field_ext_info> candidates(PSI_INSTRUMENT_MEM); /* Select from partition_list all candidates for splitting. @@ -712,7 +712,7 @@ void JOIN::add_keyuses_for_splitting() KEY_FIELD *added_key_field; if (!spl_opt_info->added_key_fields.elements) goto err; - if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>)) + if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>(PSI_INSTRUMENT_MEM))) goto err; while ((added_key_field= li++)) { @@ -742,13 +742,11 @@ void JOIN::add_keyuses_for_splitting() save_query_plan(save_qep); if (!keyuse.buffer && - my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64, - MYF(MY_THREAD_SPECIFIC))) + my_init_dynamic_array(PSI_INSTRUMENT_ME, &keyuse, sizeof(KEYUSE), + 20, 64, MYF(MY_THREAD_SPECIFIC))) goto err; - if (allocate_dynamic(&keyuse, - save_qep->keyuse.elements + - added_keyuse_count)) + if (allocate_dynamic(&keyuse, save_qep->keyuse.elements + added_keyuse_count)) goto err; memcpy(keyuse.buffer, diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index c7d95fdadec..6c491300d17 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4470,8 +4470,8 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) using_unique_constraint= TRUE; /* STEP 3: Allocate memory for temptable description */ - init_sql_alloc(&own_root, "SJ_TMP_TABLE", - TABLE_ALLOC_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(PSI_INSTRUMENT_ME, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0, + MYF(MY_THREAD_SPECIFIC)); if (!multi_alloc_root(&own_root, &table, sizeof(*table), &share, sizeof(*share), diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc index 7ff11e65a30..057c6f3cc0a 100644 --- a/sql/opt_trace.cc +++ b/sql/opt_trace.cc @@ -449,7 +449,7 @@ bool Opt_trace_context::is_enabled() return false; } -Opt_trace_context::Opt_trace_context() +Opt_trace_context::Opt_trace_context() : traces(PSI_INSTRUMENT_MEM) { current_trace= NULL; max_mem_size= 0; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 252744a3a73..5e3c19850de 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -30,7 +30,6 @@ // NOT_A_PARTITION_ID #include "partition_info.h" #include "sql_parse.h" -#include "sql_acl.h" // *_ACL #include "sql_base.h" // fill_record #include "lock.h" #include "table.h" @@ -733,7 +732,7 @@ char *partition_info::find_duplicate_name() max_names= num_parts; if (is_sub_partitioned()) max_names+= num_parts * num_subparts; - if (my_hash_init(&partition_names, system_charset_info, max_names, 0, 0, + if (my_hash_init(PSI_INSTRUMENT_ME, &partition_names, system_charset_info, max_names, 0, 0, (my_hash_get_key) get_part_name_from_elem, 0, HASH_UNIQUE)) { DBUG_ASSERT(0); diff --git a/sql/privilege.h b/sql/privilege.h index 6f12546796e..c5c13186743 100644 --- a/sql/privilege.h +++ b/sql/privilege.h @@ -49,7 +49,7 @@ enum privilege_t: unsigned long long LOCK_TABLES_ACL = (1UL << 17), EXECUTE_ACL = (1UL << 18), REPL_SLAVE_ACL = (1UL << 19), - REPL_CLIENT_ACL = (1UL << 20), + BINLOG_MONITOR_ACL = (1UL << 20), // Was REPL_CLIENT_ACL prior to 10.5.2 CREATE_VIEW_ACL = (1UL << 21), SHOW_VIEW_ACL = (1UL << 22), CREATE_PROC_ACL = (1UL << 23), @@ -58,20 +58,66 @@ enum privilege_t: unsigned long long EVENT_ACL = (1UL << 26), TRIGGER_ACL = (1UL << 27), CREATE_TABLESPACE_ACL = (1UL << 28), - DELETE_HISTORY_ACL = (1UL << 29), + DELETE_HISTORY_ACL = (1UL << 29), // Added in 10.3.4 + SET_USER_ACL = (1UL << 30), // Added in 10.5.2 + FEDERATED_ADMIN_ACL = (1UL << 31), // Added in 10.5.2 + CONNECTION_ADMIN_ACL = (1ULL << 32), // Added in 10.5.2 + READ_ONLY_ADMIN_ACL = (1ULL << 33), // Added in 10.5.2 + REPL_SLAVE_ADMIN_ACL = (1ULL << 34), // Added in 10.5.2 + REPL_MASTER_ADMIN_ACL = (1ULL << 35), // Added in 10.5.2 + BINLOG_ADMIN_ACL = (1ULL << 36) // Added in 10.5.2 /* - don't forget to update - 1. static struct show_privileges_st sys_privileges[] - 2. static const char *command_array[] and static uint command_lengths[] - 3. mysql_system_tables.sql and mysql_system_tables_fix.sql - 4. acl_init() or whatever - to define behaviour for old privilege tables - 5. sql_yacc.yy - for GRANT/REVOKE to work - 6. ALL_KNOWN_ACL + When adding new privilege bits, don't forget to update: + In this file: + - Add a new LAST_version_ACL + - Add a new ALL_KNOWN_ACL_version + - Change ALL_KNOWN_ACL to ALL_KNOWN_ACL_version + - Change GLOBAL_ACLS if needed + - Change SUPER_ADDED_SINCE_USER_TABLE_ACL if needed + + In other files: + - static struct show_privileges_st sys_privileges[] + - static const char *command_array[] and static uint command_lengths[] + - mysql_system_tables.sql and mysql_system_tables_fix.sql + - acl_init() or whatever - to define behaviour for old privilege tables + - Update User_table_json::get_access() + - sql_yacc.yy - for GRANT/REVOKE to work + + Important: the enum should contain only single-bit values. + In this case, debuggers print bit combinations in the readable form: + (gdb) p (privilege_t) (15) + $8 = (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL) + + Bit-OR combinations of the above values should be declared outside! */ - ALL_KNOWN_ACL = (1UL << 30) - 1 // A combination of all defined bits }; +// Version markers +constexpr privilege_t LAST_100304_ACL= DELETE_HISTORY_ACL; +constexpr privilege_t LAST_100502_ACL= BINLOG_ADMIN_ACL; + +// Current version markers +constexpr privilege_t LAST_CURRENT_ACL= LAST_100502_ACL; +constexpr uint PRIVILEGE_T_MAX_BIT= + my_bit_log2_uint64((ulonglong) LAST_CURRENT_ACL); + +static_assert((privilege_t)(1ULL << PRIVILEGE_T_MAX_BIT) == LAST_CURRENT_ACL, + "Something went fatally badly: " + "LAST_CURRENT_ACL and PRIVILEGE_T_MAX_BIT do not match"); + +// A combination of all bits defined in 10.3.4 (and earlier) +constexpr privilege_t ALL_KNOWN_ACL_100304 = + (privilege_t) ((LAST_100304_ACL << 1) - 1); + +// A combination of all bits defined in 10.5.2 +constexpr privilege_t ALL_KNOWN_ACL_100502= + (privilege_t) ((LAST_100502_ACL << 1) - 1); + +// A combination of all bits defined as of the current version +constexpr privilege_t ALL_KNOWN_ACL= ALL_KNOWN_ACL_100502; + + // Unary operators static inline constexpr ulonglong operator~(privilege_t access) { @@ -168,6 +214,19 @@ static inline privilege_t& operator|=(privilege_t &a, privilege_t b) } +/* + A combination of all SUPER privileges added since the old user table format. + These privileges are automatically added when upgrading from the + old format mysql.user table if a user has the SUPER privilege. +*/ +constexpr privilege_t GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS= + SET_USER_ACL | + FEDERATED_ADMIN_ACL | + CONNECTION_ADMIN_ACL | + READ_ONLY_ADMIN_ACL | + REPL_SLAVE_ADMIN_ACL | + BINLOG_ADMIN_ACL; + constexpr privilege_t COL_DML_ACLS= SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL; @@ -206,7 +265,9 @@ constexpr privilege_t GLOBAL_ACLS= DB_ACLS | SHOW_DB_ACL | CREATE_USER_ACL | CREATE_TABLESPACE_ACL | SUPER_ACL | RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | - REPL_SLAVE_ACL | REPL_CLIENT_ACL; + REPL_SLAVE_ACL | BINLOG_MONITOR_ACL | + GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS | + REPL_MASTER_ADMIN_ACL; constexpr privilege_t DEFAULT_CREATE_PROC_ACLS= ALTER_PROC_ACL | EXECUTE_ACL; @@ -222,6 +283,124 @@ constexpr privilege_t SHOW_CREATE_TABLE_ACLS= constexpr privilege_t TMP_TABLE_ACLS= COL_DML_ACLS | ALL_TABLE_DDL_ACLS; + + +/* + Allow to set an object definer: + CREATE DEFINER=xxx {TRIGGER|VIEW|FUNCTION|PROCEDURE} + Was SUPER prior to 10.5.2 +*/ +constexpr privilege_t PRIV_DEFINER_CLAUSE= SET_USER_ACL | SUPER_ACL; +/* + If a VIEW has a `definer=invoker@host` clause and + the specified definer does not exists, then + - The invoker with REVEAL_MISSING_DEFINER_ACL gets: + ERROR: The user specified as a definer ('definer1'@'localhost') doesn't exist + - The invoker without MISSING_DEFINER_ACL gets a generic access error, + without revealing details that the definer does not exists. + + TODO: we should eventually test the same privilege when processing + other objects that have the DEFINER clause (e.g. routines, triggers). + Currently the missing definer is revealed for non-privileged invokers + in case of routines, triggers, etc. + + Was SUPER prior to 10.5.2 +*/ +constexpr privilege_t PRIV_REVEAL_MISSING_DEFINER= SET_USER_ACL | SUPER_ACL; + +/* Actions that require only the SUPER privilege */ +constexpr privilege_t PRIV_DES_DECRYPT_ONE_ARG= SUPER_ACL; +constexpr privilege_t PRIV_LOG_BIN_TRUSTED_SP_CREATOR= SUPER_ACL; +constexpr privilege_t PRIV_DEBUG= SUPER_ACL; +constexpr privilege_t PRIV_SET_GLOBAL_SYSTEM_VARIABLE= SUPER_ACL; +constexpr privilege_t PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE= SUPER_ACL; + +/* Privileges related to --read-only */ +constexpr privilege_t PRIV_IGNORE_READ_ONLY= READ_ONLY_ADMIN_ACL | SUPER_ACL; + +/* + Privileges related to connection handling. +*/ +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_IGNORE_INIT_CONNECT= CONNECTION_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_IGNORE_MAX_USER_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_IGNORE_MAX_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_IGNORE_MAX_PASSWORD_ERRORS= CONNECTION_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_KILL_OTHER_USER_PROCESS= CONNECTION_ADMIN_ACL | SUPER_ACL; + + +/* + Binary log related privileges that are checked regardless + of active replication running. +*/ + +/* + This command was renamed from "SHOW MASTER STATUS" + to "SHOW BINLOG STATUS" in 10.5.2. + Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2 + REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL. +*/ +constexpr privilege_t PRIV_STMT_SHOW_BINLOG_STATUS= BINLOG_MONITOR_ACL | SUPER_ACL; + +/* + Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2 + REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL. +*/ +constexpr privilege_t PRIV_STMT_SHOW_BINARY_LOGS= BINLOG_MONITOR_ACL | SUPER_ACL; + +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_PURGE_BINLOG= BINLOG_ADMIN_ACL | SUPER_ACL; + +// Was REPL_SLAVE_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_SHOW_BINLOG_EVENTS= BINLOG_MONITOR_ACL; + + +/* + Privileges for replication related statements and commands + that are executed on the master. +*/ +constexpr privilege_t PRIV_COM_REGISTER_SLAVE= REPL_SLAVE_ACL; +constexpr privilege_t PRIV_COM_BINLOG_DUMP= REPL_SLAVE_ACL; +// Was REPL_SLAVE_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_SHOW_SLAVE_HOSTS= REPL_MASTER_ADMIN_ACL; + + +/* Privileges for statements that are executed on the slave */ +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_START_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_STOP_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_CHANGE_MASTER= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; +// Was (SUPER_ACL | REPL_CLIENT_ACL) prior to 10.5.2 +constexpr privilege_t PRIV_STMT_SHOW_SLAVE_STATUS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_BINLOG= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; +// Was REPL_SLAVE_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_SHOW_RELAYLOG_EVENTS= REPL_SLAVE_ADMIN_ACL; + + +/* Privileges for federated database related statements */ +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_CREATE_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_ALTER_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; +// Was SUPER_ACL prior to 10.5.2 +constexpr privilege_t PRIV_STMT_DROP_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; + + +/* Privileges related to processes */ +constexpr privilege_t PRIV_COM_PROCESS_INFO= PROCESS_ACL; +constexpr privilege_t PRIV_STMT_SHOW_EXPLAIN= PROCESS_ACL; +constexpr privilege_t PRIV_STMT_SHOW_ENGINE_STATUS= PROCESS_ACL; +constexpr privilege_t PRIV_STMT_SHOW_ENGINE_MUTEX= PROCESS_ACL; +constexpr privilege_t PRIV_STMT_SHOW_PROCESSLIST= PROCESS_ACL; + + /* Defines to change the above bits to how things are stored in tables This is needed as the 'host' and 'db' table is missing a few privileges diff --git a/sql/protocol.cc b/sql/protocol.cc index 30e4cc6c214..21efac46c52 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -799,6 +799,41 @@ bool Protocol::flush() #ifndef EMBEDDED_LIBRARY + +class Send_field_packed_extended_metadata: public Binary_string +{ +public: + bool append_chunk(mariadb_field_attr_t type, const LEX_CSTRING &value) + { + /* + If we eventually support many metadata chunk types and long metadata + values, we'll need to encode type and length using net_store_length() + and do corresponding changes to the unpacking code in libmariadb. + For now let's just assert that type and length fit into one byte. + */ + DBUG_ASSERT(net_length_size(type) == 1); + DBUG_ASSERT(net_length_size(value.length) == 1); + size_t nbytes= 1/*type*/ + 1/*length*/ + value.length; + if (reserve(nbytes)) + return true; + qs_append((char) (uchar) type); + qs_append((char) (uchar) value.length); + qs_append(&value); + return false; + } + bool pack(const Send_field_extended_metadata &src) + { + for (uint i= 0 ; i <= MARIADB_FIELD_ATTR_LAST; i++) + { + const LEX_CSTRING attr= src.attr(i); + if (attr.str && append_chunk((mariadb_field_attr_t) i, attr)) + return true; + } + return false; + } +}; + + bool Protocol_text::store_field_metadata(const THD * thd, const Send_field &field, CHARSET_INFO *charset_for_protocol, @@ -816,8 +851,20 @@ bool Protocol_text::store_field_metadata(const THD * thd, store_str(field.table_name, cs, thd_charset) || store_str(field.org_table_name, cs, thd_charset) || store_str(field.col_name, cs, thd_charset) || - store_str(field.org_col_name, cs, thd_charset) || - packet->realloc(packet->length() + 12)) + store_str(field.org_col_name, cs, thd_charset)) + return true; + if (thd->client_capabilities & MARIADB_CLIENT_EXTENDED_METADATA) + { + Send_field_packed_extended_metadata metadata; + metadata.pack(field); + /* + Don't apply character set conversion: + extended metadata is a binary encoded data. + */ + if (store_str(metadata.lex_cstring(), cs, &my_charset_bin)) + return true; + } + if (packet->realloc(packet->length() + 12)) return true; /* Store fixed length fields */ pos= (char*) packet->end(); diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index 550813c6457..689d1af88f0 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -364,7 +364,8 @@ static int parse_networks(const char *subnets_str, subnet **out_subnets, size_t } max_subnets= MY_MAX(3,strlen(subnets_str)/2); - subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL); + subnets= (subnet *)my_malloc(PSI_INSTRUMENT_ME, + max_subnets * sizeof(subnet), MY_ZEROFILL); /* Check for special case '*'. */ if (strcmp(subnets_str, "*") == 0) diff --git a/sql/records.cc b/sql/records.cc index 2b146abb005..e1766322e2f 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -39,7 +39,7 @@ static int rr_quick(READ_RECORD *info); int rr_sequential(READ_RECORD *info); static int rr_from_tempfile(READ_RECORD *info); template<bool> static int rr_unpack_from_tempfile(READ_RECORD *info); -template<bool> static int rr_unpack_from_buffer(READ_RECORD *info); +template<bool,bool> static int rr_unpack_from_buffer(READ_RECORD *info); int rr_from_pointers(READ_RECORD *info); static int rr_from_cache(READ_RECORD *info); static int init_rr_cache(THD *thd, READ_RECORD *info); @@ -190,6 +190,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, DBUG_ENTER("init_read_record"); const bool using_addon_fields= filesort && filesort->using_addon_fields(); + bool using_packed_sortkeys= filesort && filesort->using_packed_sortkeys(); bzero((char*) info,sizeof(*info)); info->thd=thd; @@ -287,10 +288,19 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, DBUG_PRINT("info",("using rr_unpack_from_buffer")); DBUG_ASSERT(filesort->sorted_result_in_fsbuf); info->unpack_counter= 0; + if (filesort->using_packed_addons()) - info->read_record_func= rr_unpack_from_buffer<true>; + { + info->read_record_func= using_packed_sortkeys ? + rr_unpack_from_buffer<true, true> : + rr_unpack_from_buffer<true, false>; + } else - info->read_record_func= rr_unpack_from_buffer<false>; + { + info->read_record_func= using_packed_sortkeys ? + rr_unpack_from_buffer<false, true> : + rr_unpack_from_buffer<false, false>; + } } else { @@ -626,7 +636,7 @@ int rr_from_pointers(READ_RECORD *info) -1 There is no record to be read anymore. */ -template<bool Packed_addon_fields> +template<bool Packed_addon_fields, bool Packed_sort_keys> static int rr_unpack_from_buffer(READ_RECORD *info) { if (info->unpack_counter == info->sort_info->return_rows) @@ -634,7 +644,12 @@ static int rr_unpack_from_buffer(READ_RECORD *info) uchar *record= info->sort_info->get_sorted_record( static_cast<uint>(info->unpack_counter)); - uchar *plen= record + info->sort_info->get_sort_length(); + + uint sort_length= Packed_sort_keys ? + Sort_keys::read_sortkey_length(record): + info->sort_info->get_sort_length(); + + uchar *plen= record + sort_length; info->sort_info->unpack_addon_fields<Packed_addon_fields>(plen); info->unpack_counter++; return 0; @@ -772,6 +787,19 @@ static int rr_cmp(uchar *a,uchar *b) #endif } + +/** + Copy (unpack) values appended to sorted fields from a buffer back to + their regular positions specified by the Field::ptr pointers. + + @param addon_field Array of descriptors for appended fields + @param buff Buffer which to unpack the value from + + @note + The function is supposed to be used only as a callback function + when getting field values for the sorted result set. + +*/ template<bool Packed_addon_fields> inline void SORT_INFO::unpack_addon_fields(uchar *buff) { diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 7905e112e2e..1df85759a9c 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -101,7 +101,7 @@ void THD::unregister_slave() mysql_mutex_lock(&LOCK_thd_data); slave_info= 0; mysql_mutex_unlock(&LOCK_thd_data); - delete old_si; + my_free(old_si); binlog_dump_thread_count--; } } @@ -122,9 +122,10 @@ int THD::register_slave(uchar *packet, size_t packet_length) uchar *p= packet, *p_end= packet + packet_length; const char *errmsg= "Wrong parameters to function register_slave"; - if (check_access(this, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0)) + if (check_access(this, PRIV_COM_REGISTER_SLAVE, any_db, NULL, NULL, 0, 0)) return 1; - if (!(si= new Slave_info)) + if (!(si= (Slave_info*)my_malloc(key_memory_SLAVE_INFO, sizeof(Slave_info), + MYF(MY_WME)))) return 1; variables.server_id= si->server_id= uint4korr(p); diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index e96f9640098..635a0f4e2d6 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -286,7 +286,7 @@ Rpl_filter::parse_filter_rule(const char* spec, Add_filter add) if (!spec) return false; - if (! (ptr= my_strdup(spec, MYF(MY_WME)))) + if (! (ptr= my_strdup(key_memory_rpl_filter, spec, MYF(MY_WME)))) return true; pstr= ptr; @@ -461,8 +461,9 @@ Rpl_filter::add_table_rule(HASH* h, const char* table_spec) if (!dot) return 1; // len is always > 0 because we know the there exists a '.' uint len = (uint)strlen(table_spec); - TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) - + len, MYF(MY_WME)); + TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(key_memory_TABLE_RULE_ENT, + sizeof(TABLE_RULE_ENT) + len, + MYF(MY_WME)); if (!e) return 1; e->db= (char*)e + sizeof(TABLE_RULE_ENT); e->tbl_name= e->db + (dot - table_spec) + 1; @@ -483,8 +484,9 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) const char* dot = strchr(table_spec, '.'); if (!dot) return 1; uint len = (uint)strlen(table_spec); - TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) - + len, MYF(MY_WME)); + TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(key_memory_TABLE_RULE_ENT, + sizeof(TABLE_RULE_ENT) + len, + MYF(MY_WME)); if (!e) return 1; e->db= (char*)e + sizeof(TABLE_RULE_ENT); e->tbl_name= e->db + (dot - table_spec) + 1; @@ -500,7 +502,7 @@ Rpl_filter::add_string_list(I_List<i_string> *list, const char* spec) char *str; i_string *node; - if (! (str= my_strdup(spec, MYF(MY_WME)))) + if (! (str= my_strdup(key_memory_rpl_filter, spec, MYF(MY_WME)))) return true; if (! (node= new i_string(str))) @@ -571,8 +573,9 @@ void free_table_ent(void* a) void Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited) { - my_hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0, - get_table_key, free_table_ent, 0); + my_hash_init(key_memory_TABLE_RULE_ENT, h, + system_charset_info,TABLE_RULE_HASH_SIZE,0,0, get_table_key, + free_table_ent, 0); *h_inited = 1; } @@ -580,8 +583,8 @@ Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited) void Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited) { - my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE, - TABLE_RULE_ARR_SIZE, MYF(0)); + my_init_dynamic_array(key_memory_TABLE_RULE_ENT, a, sizeof(TABLE_RULE_ENT*), + TABLE_RULE_ARR_SIZE, TABLE_RULE_ARR_SIZE, MYF(0)); *a_inited = 1; } diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 599129b98f4..bc87441d183 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -248,9 +248,10 @@ rpl_slave_state::rpl_slave_state() { mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state, MY_MUTEX_INIT_SLOW); - my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), + my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id), sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE); - my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid), + 8, 8, MYF(0)); } @@ -333,7 +334,8 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id, rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL; } - if (!(list_elem= (list_element *)my_malloc(sizeof(*list_elem), MYF(MY_WME)))) + if (!(list_elem= (list_element *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(*list_elem), MYF(MY_WME)))) return 1; list_elem->domain_id= domain_id; list_elem->server_id= server_id; @@ -367,7 +369,7 @@ rpl_slave_state::get_element(uint32 domain_id) if (elem) return elem; - if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME)))) + if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME)))) return NULL; elem->list= NULL; elem->domain_id= domain_id; @@ -1111,8 +1113,9 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data, int res= 1; bool locked= false; - my_hash_init(>id_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id), - sizeof(uint32), NULL, NULL, HASH_UNIQUE); + my_hash_init(PSI_INSTRUMENT_ME, >id_hash, &my_charset_bin, 32, + offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, NULL, + HASH_UNIQUE); for (i= 0; i < num_extra; ++i) if (extra_gtids[i].server_id == global_system_variables.server_id && my_hash_insert(>id_hash, (uchar *)(&extra_gtids[i]))) @@ -1329,7 +1332,7 @@ gtid_parse_string_to_list(const char *str, size_t str_len, uint32 *out_len) } if ((!list || len >= alloc_len) && !(list= - (rpl_gtid *)my_realloc(list, + (rpl_gtid *)my_realloc(PSI_INSTRUMENT_ME, list, (alloc_len= alloc_len*2) * sizeof(rpl_gtid), MYF(MY_FREE_ON_ERROR|MY_ALLOW_ZERO_PTR)))) return NULL; @@ -1466,10 +1469,8 @@ rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton, struct gtid_pos_table *p; char *allocated_str; - if (!my_multi_malloc(MYF(MY_WME), - &p, sizeof(*p), - &allocated_str, table_name->length+1, - NULL)) + if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &p, sizeof(*p), + &allocated_str, table_name->length+1, NULL)) { my_error(ER_OUTOFMEMORY, MYF(0), (int)(sizeof(*p) + table_name->length+1)); return NULL; @@ -1486,9 +1487,9 @@ rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton, void rpl_binlog_state::init() { - my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id), + my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); - my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state, MY_MUTEX_INIT_SLOW); initialized= 1; @@ -1685,7 +1686,8 @@ rpl_binlog_state::element::update_element(const rpl_gtid *gtid) } /* Allocate a new GTID and insert it. */ - lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME)); + lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid), + MYF(MY_WME)); if (!lookup_gtid) return 1; memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid)); @@ -1706,12 +1708,13 @@ rpl_binlog_state::alloc_element_nolock(const rpl_gtid *gtid) rpl_gtid *lookup_gtid; /* First time we see this domain_id; allocate a new element. */ - elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME)); - lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME)); + elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME)); + lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid), + MYF(MY_WME)); if (elem && lookup_gtid) { elem->domain_id= gtid->domain_id; - my_hash_init(&elem->hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32, offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); elem->last_gtid= lookup_gtid; @@ -1784,14 +1787,15 @@ rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no) } /* We need to allocate a new, empty element to remember the next seq_no. */ - if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME)))) + if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), + MYF(MY_WME)))) { res= 1; goto end; } elem->domain_id= domain_id; - my_hash_init(&elem->hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32, offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); elem->last_gtid= NULL; @@ -2006,8 +2010,8 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size) out_size= 0; mysql_mutex_lock(&LOCK_binlog_state); alloc_size= hash.records; - if (!(*list= (rpl_gtid *)my_malloc(alloc_size * sizeof(rpl_gtid), - MYF(MY_WME)))) + if (!(*list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + alloc_size * sizeof(rpl_gtid), MYF(MY_WME)))) { res= 1; goto end; @@ -2122,7 +2126,7 @@ rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids, DBUG_ENTER("rpl_binlog_state::drop_domain"); - my_init_dynamic_array2(&domain_unique, + my_init_dynamic_array2(PSI_INSTRUMENT_ME, &domain_unique, sizeof(element*), domain_unique_buffer, sizeof(domain_unique_buffer) / sizeof(element*), 4, 0); @@ -2247,10 +2251,10 @@ end: slave_connection_state::slave_connection_state() { - my_hash_init(&hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); - my_init_dynamic_array(>id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0)); } @@ -2294,7 +2298,7 @@ slave_connection_state::load(const char *slave_request, size_t len) return 0; for (;;) { - if (!(rec= (uchar *)my_malloc(sizeof(entry), MYF(MY_WME)))) + if (!(rec= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sizeof(entry), MYF(MY_WME)))) return 1; gtid= &((entry *)rec)->gtid; if (gtid_parser_helper(&p, end, gtid)) @@ -2397,7 +2401,7 @@ slave_connection_state::update(const rpl_gtid *in_gtid) return 0; } - if (!(e= (entry *)my_malloc(sizeof(*e), MYF(MY_WME)))) + if (!(e= (entry *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME)))) return 1; e->gtid= *in_gtid; e->flags= 0; @@ -2873,7 +2877,7 @@ free_hash_element(void *p) void gtid_waiting::init() { - my_hash_init(&hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(hash_element, domain_id), sizeof(uint32), NULL, free_hash_element, HASH_UNIQUE); mysql_mutex_init(key_LOCK_gtid_waiting, &LOCK_gtid_waiting, 0); @@ -2910,7 +2914,7 @@ gtid_waiting::get_entry(uint32 domain_id) if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id, 0))) return e; - if (!(e= (hash_element *)my_malloc(sizeof(*e), MYF(MY_WME)))) + if (!(e= (hash_element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME)))) return NULL; if (init_queue(&e->queue, 8, offsetof(queue_element, wait_seq_no), 0, diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 167d7461a7e..523af4856ae 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -27,6 +27,8 @@ extern const LEX_CSTRING rpl_gtid_slave_state_table_name; class String; +#define GTID_MAX_STR_LENGTH (10+1+10+1+20) + struct rpl_gtid { uint32 domain_id; diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index 597a357e4e2..b0b6e30bed6 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -37,7 +37,8 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd) LOG_INFO log_info; log->get_current_log(&log_info); /* !!! binlog_pos does not follow RAII !!! */ - m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0)); + m_start_pos.m_file_name= my_strdup(key_memory_binlog_pos, + log_info.log_file_name, MYF(0)); m_start_pos.m_file_pos= log_info.pos; m_thd->lex->start_transaction_opt= 0; /* for begin_trans() */ diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 43a02147496..0649a8f05e8 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -58,7 +58,7 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg, connection_name.length= cmp_connection_name.length= connection_name_arg->length; if ((connection_name.str= tmp= (char*) - my_malloc(connection_name_arg->length*2+2, MYF(MY_WME)))) + my_malloc(PSI_INSTRUMENT_ME, connection_name_arg->length*2+2, MYF(MY_WME)))) { strmake(tmp, connection_name_arg->str, connection_name.length); tmp+= connection_name_arg->length+1; @@ -77,7 +77,7 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg, parallel_mode= rpl_filter->get_parallel_mode(); - my_init_dynamic_array(&ignore_server_ids, + my_init_dynamic_array(PSI_INSTRUMENT_ME, &ignore_server_ids, sizeof(global_system_variables.server_id), 16, 16, MYF(0)); bzero((char*) &file, sizeof(file)); @@ -742,7 +742,8 @@ int flush_master_info(Master_info* mi, char* ignore_server_ids_buf; { ignore_server_ids_buf= - (char *) my_malloc((sizeof(global_system_variables.server_id) * 3 + 1) * + (char *) my_malloc(PSI_INSTRUMENT_ME, + (sizeof(global_system_variables.server_id) * 3 + 1) * (1 + mi->ignore_server_ids.elements), MYF(MY_WME)); if (!ignore_server_ids_buf) DBUG_RETURN(1); /* error */ @@ -1098,7 +1099,7 @@ bool Master_info_index::init_all_master_info() } /* Initialize Master_info Hash Table */ - if (my_hash_init(&master_info_hash, system_charset_info, + if (my_hash_init(PSI_INSTRUMENT_ME, &master_info_hash, system_charset_info, MAX_REPLICATION_THREAD, 0, 0, (my_hash_get_key) get_key_master_info, (my_hash_free_key)free_key_master_info, HASH_UNIQUE)) @@ -1570,6 +1571,8 @@ uint any_slave_sql_running(bool already_locked) if (!already_locked) mysql_mutex_lock(&LOCK_active_mi); + else + mysql_mutex_assert_owner(&LOCK_active_mi); if (unlikely(abort_loop || !master_info_index)) count= 1; else @@ -1739,7 +1742,8 @@ Domain_id_filter::Domain_id_filter() : m_filter(false) { for (int i= DO_DOMAIN_IDS; i <= IGNORE_DOMAIN_IDS; i ++) { - my_init_dynamic_array(&m_domain_ids[i], sizeof(ulong), 16, 16, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_domain_ids[i], sizeof(ulong), + 16, 16, MYF(0)); } } @@ -1902,7 +1906,7 @@ char *Domain_id_filter::as_string(enum_list_type type) sz= (sizeof(ulong) * 3 + 1) * (1 + ids->elements); - if (!(buf= (char *) my_malloc(sz, MYF(MY_WME)))) + if (!(buf= (char *) my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME)))) return NULL; // Store the total number of elements followed by the individual elements. diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 4313840119e..f875ab2b4a4 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1557,7 +1557,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool, to allocate, and will not be left with a half-functional thread pool. */ if (new_count && - !my_multi_malloc(MYF(MY_WME|MY_ZEROFILL), + !my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME|MY_ZEROFILL), &new_list, new_count*sizeof(*new_list), &rpt_array, new_count*sizeof(*rpt_array), NULL)) @@ -1789,7 +1789,7 @@ rpl_parallel_thread::get_qev_common(Log_event *ev, ulonglong event_size) mysql_mutex_assert_owner(&LOCK_rpl_thread); if ((qev= qev_free_list)) qev_free_list= qev->next; - else if(!(qev= (queued_event *)my_malloc(sizeof(*qev), MYF(0)))) + else if(!(qev= (queued_event *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*qev), MYF(0)))) { my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*qev)); return NULL; @@ -1952,7 +1952,7 @@ rpl_parallel_thread::get_gco(uint64 wait_count, group_commit_orderer *prev, mysql_mutex_assert_owner(&LOCK_rpl_thread); if ((gco= gco_free_list)) gco_free_list= gco->next_gco; - else if(!(gco= (group_commit_orderer *)my_malloc(sizeof(*gco), MYF(0)))) + else if(!(gco= (group_commit_orderer *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*gco), MYF(0)))) { my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*gco)); return NULL; @@ -2199,7 +2199,7 @@ free_rpl_parallel_entry(void *element) rpl_parallel::rpl_parallel() : current(NULL), sql_thread_stopping(false) { - my_hash_init(&domain_hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &domain_hash, &my_charset_bin, 32, offsetof(rpl_parallel_entry, domain_id), sizeof(uint32), NULL, free_rpl_parallel_entry, HASH_UNIQUE); } @@ -2233,7 +2233,7 @@ rpl_parallel::find(uint32 domain_id) if (count == 0 || count > opt_slave_parallel_threads) count= opt_slave_parallel_threads; rpl_parallel_thread **p; - if (!my_multi_malloc(MYF(MY_WME|MY_ZEROFILL), + if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME|MY_ZEROFILL), &e, sizeof(*e), &p, count*sizeof(*p), NULL)) diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 6d55b06b497..01093d9a6da 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -73,7 +73,9 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) key_RELAYLOG_COND_relay_log_updated, key_RELAYLOG_COND_bin_log_updated, key_file_relaylog, + key_file_relaylog_cache, key_file_relaylog_index, + key_file_relaylog_index_cache, key_RELAYLOG_COND_queue_busy, key_LOCK_relaylog_end_pos); #endif @@ -1435,14 +1437,15 @@ Relay_log_info::alloc_inuse_relaylog(const char *name) uint32 gtid_count; rpl_gtid *gtid_list; - if (!(ir= (inuse_relaylog *)my_malloc(sizeof(*ir), MYF(MY_WME|MY_ZEROFILL)))) + if (!(ir= (inuse_relaylog *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*ir), + MYF(MY_WME|MY_ZEROFILL)))) { my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*ir)); return 1; } gtid_count= relay_log_state.count(); - if (!(gtid_list= (rpl_gtid *)my_malloc(sizeof(*gtid_list)*gtid_count, - MYF(MY_WME)))) + if (!(gtid_list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(*gtid_list)*gtid_count, MYF(MY_WME)))) { my_free(ir); my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*gtid_list)*gtid_count); @@ -1589,8 +1592,8 @@ scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array, } else { - if (!(entry= (struct gtid_pos_element *)my_malloc(sizeof(*entry), - MYF(MY_WME)))) + if (!(entry= (struct gtid_pos_element *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(*entry), MYF(MY_WME)))) { my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*entry)); err= 1; @@ -1831,10 +1834,11 @@ rpl_load_gtid_slave_state(THD *thd) cb_data.table_list= NULL; cb_data.default_entry= NULL; - my_hash_init(&hash, &my_charset_bin, 32, + my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(gtid_pos_element, gtid) + offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, my_free, HASH_UNIQUE); - if ((err= my_init_dynamic_array(&array, sizeof(gtid_pos_element), 0, 0, MYF(0)))) + if ((err= my_init_dynamic_array(PSI_INSTRUMENT_ME, &array, + sizeof(gtid_pos_element), 0, 0, MYF(0)))) goto end; array_inited= true; diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index b2da9092e3a..a230b9f6f29 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -34,6 +34,12 @@ table_mapping::table_mapping() : m_free(0) { +#ifdef MYSQL_CLIENT + PSI_memory_key psi_key= PSI_NOT_INSTRUMENTED; +#else + PSI_memory_key psi_key= key_memory_table_mapping_root; +#endif + DBUG_ENTER("table_mapping::table_mapping"); /* No "free_element" function for entries passed here, as the entries are @@ -42,12 +48,11 @@ table_mapping::table_mapping() Note that below we don't test if my_hash_init() succeeded. This constructor is called at startup only. */ - (void) my_hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE, + (void) my_hash_init(psi_key, &m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE, offsetof(entry,table_id),sizeof(ulonglong), - 0,0,0); + 0,0,0); /* We don't preallocate any block, this is consistent with m_free=0 above */ - init_alloc_root(&m_mem_root, "table_mapping", - TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0)); + init_alloc_root(psi_key, &m_mem_root, TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0)); DBUG_VOID_RETURN; } diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 1e4b59844b8..7c347eba51f 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -171,6 +171,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const return length; } +PSI_memory_key key_memory_table_def_memory; table_def::table_def(unsigned char *types, ulong size, uchar *field_metadata, int metadata_size, @@ -179,7 +180,7 @@ table_def::table_def(unsigned char *types, ulong size, m_field_metadata(0), m_null_bits(0), m_flags(flags), m_memory(NULL) { - m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), + m_memory= (uchar *)my_multi_malloc(key_memory_table_def_memory, MYF(MY_WME), &m_type, size, &m_field_metadata, size * sizeof(uint16), diff --git a/sql/rpl_utility_server.cc b/sql/rpl_utility_server.cc index e58c9cf018e..8110b142e74 100644 --- a/sql/rpl_utility_server.cc +++ b/sql/rpl_utility_server.cc @@ -1123,7 +1123,7 @@ err: Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL) { - my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &array, sizeof(Log_event *), 32, 16, MYF(0)); } Deferred_log_events::~Deferred_log_events() diff --git a/sql/scheduler.h b/sql/scheduler.h index 676262f6454..ebf8d6e9e64 100644 --- a/sql/scheduler.h +++ b/sql/scheduler.h @@ -82,17 +82,6 @@ extern void post_kill_notification(THD *); struct thd_scheduler { public: - /* - Thread instrumentation for the user job. - This member holds the instrumentation while the user job is not run - by a thread. - - Note that this member is not conditionally declared - (ifdef HAVE_PSI_INTERFACE), because doing so will change the binary - layout of THD, which is exposed to plugin code that may be compiled - differently. - */ - PSI_thread *m_psi; void *data; /* scheduler-specific data structure */ }; diff --git a/sql/select_handler.cc b/sql/select_handler.cc index c8f92461fd0..4d2cacd1a6e 100644 --- a/sql/select_handler.cc +++ b/sql/select_handler.cc @@ -77,18 +77,17 @@ bool Pushdown_select::init() bool Pushdown_select::send_result_set_metadata() { - THD *thd= handler->thd; - Protocol *protocol= thd->protocol; DBUG_ENTER("Pushdown_select::send_result_set_metadata"); #ifdef WITH_WSREP + THD *thd= handler->thd; if (WSREP(thd) && thd->wsrep_retry_query) { WSREP_DEBUG("skipping select metadata"); DBUG_RETURN(false); } #endif /* WITH_WSREP */ - if (protocol->send_result_set_metadata(&result_columns, + if (select->join->result->send_result_set_metadata(result_columns, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(true); @@ -99,21 +98,10 @@ bool Pushdown_select::send_result_set_metadata() bool Pushdown_select::send_data() { - THD *thd= handler->thd; - Protocol *protocol= thd->protocol; DBUG_ENTER("Pushdown_select::send_data"); - protocol->prepare_for_resend(); - if (protocol->send_result_set_row(&result_columns)) - { - protocol->remove_last_row(); + if (select->join->result->send_data(result_columns)) DBUG_RETURN(true); - } - - thd->inc_sent_row_count(1); - - if (thd->vio_ok()) - DBUG_RETURN(protocol->write()); DBUG_RETURN(false); } @@ -121,16 +109,10 @@ bool Pushdown_select::send_data() bool Pushdown_select::send_eof() { - THD *thd= handler->thd; DBUG_ENTER("Pushdown_select::send_eof"); - /* - Don't send EOF if we're in error condition (which implies we've already - sent or are sending an error) - */ - if (thd->is_error()) + if (select->join->result->send_eof()) DBUG_RETURN(true); - ::my_eof(thd); DBUG_RETURN(false); } diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc index b239a9776a7..79634d142eb 100644 --- a/sql/semisync_master.cc +++ b/sql/semisync_master.cc @@ -724,8 +724,8 @@ int Repl_semi_sync_master::report_binlog_update(THD* thd, const char *log_file, if (!(log_info= thd->semisync_info)) { - if(!(log_info= - (Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0)))) + if(!(log_info= (Trans_binlog_info*)my_malloc(PSI_INSTRUMENT_ME, + sizeof(Trans_binlog_info), MYF(0)))) return 1; thd->semisync_info= log_info; } diff --git a/sql/semisync_master.h b/sql/semisync_master.h index 74f6c24c8ea..9f0acf57a60 100644 --- a/sql/semisync_master.h +++ b/sql/semisync_master.h @@ -231,7 +231,7 @@ private: */ int allocate_block() { - Block *block= (Block *)my_malloc(sizeof(Block), MYF(0)); + Block *block= (Block *)my_malloc(PSI_INSTRUMENT_ME, sizeof(Block), MYF(0)); if (block) { block->next= NULL; diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc index e189fc5f631..6340b4bd661 100644 --- a/sql/semisync_master_ack_receiver.cc +++ b/sql/semisync_master_ack_receiver.cc @@ -164,7 +164,7 @@ void Ack_receiver::remove_slave(THD *thd) inline void Ack_receiver::set_stage_info(const PSI_stage_info &stage) { - MYSQL_SET_STAGE(stage.m_key, __FILE__, __LINE__); + (void)MYSQL_SET_STAGE(stage.m_key, __FILE__, __LINE__); } inline void Ack_receiver::wait_for_slave_connection() diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 33ee6141658..e1c2ec37644 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -72,7 +72,8 @@ void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd) bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) { sysvar_node_st *node; - if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), + if (!(node= (sysvar_node_st *) my_malloc(PSI_INSTRUMENT_ME, + sizeof(sysvar_node_st), MYF(MY_WME | (mysqld_server_initialized ? MY_THREAD_SPECIFIC : 0))))) @@ -326,7 +327,8 @@ void Session_sysvars_tracker::init(THD *thd) global_system_variables.session_track_system_variables); DBUG_ASSERT(global_system_variables.session_track_system_variables); thd->variables.session_track_system_variables= - my_strdup(global_system_variables.session_track_system_variables, + my_strdup(PSI_INSTRUMENT_ME, + global_system_variables.session_track_system_variables, MYF(MY_WME | MY_THREAD_SPECIFIC)); } @@ -383,11 +385,11 @@ bool Session_sysvars_tracker::update(THD *thd, set_var *var) size_t length= 1; if (var->save_result.string_value.str) - copy= my_memdup(var->save_result.string_value.str, + copy= my_memdup(PSI_INSTRUMENT_ME, var->save_result.string_value.str, (length= var->save_result.string_value.length + 1), MYF(MY_WME | MY_THREAD_SPECIFIC)); else - copy= my_strdup("", MYF(MY_WME | MY_THREAD_SPECIFIC)); + copy= my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME | MY_THREAD_SPECIFIC)); if (!copy) return true; diff --git a/sql/session_tracker.h b/sql/session_tracker.h index b91e588a34e..7db1feb1b1a 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -142,10 +142,9 @@ class Session_sysvars_tracker: public State_tracker bool track_all; void init() { - my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0, - (my_hash_get_key) sysvars_get_key, my_free, - HASH_UNIQUE | (mysqld_server_initialized ? - HASH_THREAD_SPECIFIC : 0)); + my_hash_init(PSI_INSTRUMENT_ME, &m_registered_sysvars, &my_charset_bin, + 0, 0, 0, (my_hash_get_key) sysvars_get_key, my_free, + HASH_UNIQUE | (mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0)); } void free_hash() { @@ -401,10 +400,9 @@ class User_variables_tracker: public State_tracker Hash_set<const user_var_entry> m_changed_user_variables; public: User_variables_tracker(): - m_changed_user_variables(&my_charset_bin, 0, 0, - sizeof(const user_var_entry*), 0, 0, - HASH_UNIQUE | (mysqld_server_initialized ? - HASH_THREAD_SPECIFIC : 0)) {} + m_changed_user_variables(PSI_INSTRUMENT_ME, &my_charset_bin, 0, 0, + sizeof(const user_var_entry*), 0, 0, HASH_UNIQUE | + mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0) {} bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); void mark_as_changed(THD *thd, const user_var_entry *var) diff --git a/sql/set_var.cc b/sql/set_var.cc index fac409f8ef9..551b92012d1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -33,7 +33,6 @@ // date_time_format_make #include "derror.h" #include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone -#include "sql_acl.h" // SUPER_ACL #include "sql_select.h" // free_underlaid_joins #include "sql_i_s.h" #include "sql_view.h" // updatable_views_with_limit_typelib @@ -43,6 +42,7 @@ static HASH system_variable_hash; static PolyLock_mutex PLock_global_system_variables(&LOCK_global_system_variables); +static ulonglong system_variable_hash_version= 0; /** Return variable name and length for hashing of variables. @@ -64,7 +64,7 @@ int sys_var_init() /* Must be already initialized. */ DBUG_ASSERT(system_charset_info != NULL); - if (my_hash_init(&system_variable_hash, system_charset_info, 700, 0, + if (my_hash_init(PSI_INSTRUMENT_ME, &system_variable_hash, system_charset_info, 700, 0, 0, (my_hash_get_key) get_sys_var_length, 0, HASH_UNIQUE)) goto error; @@ -583,6 +583,8 @@ int mysql_add_sys_var_chain(sys_var *first) goto error; } } + /* Update system_variable_hash version. */ + system_variable_hash_version++; return 0; error: @@ -613,6 +615,8 @@ int mysql_del_sys_var_chain(sys_var *first) result|= my_hash_delete(&system_variable_hash, (uchar*) var); mysql_prlock_unlock(&LOCK_system_variables_hash); + /* Update system_variable_hash version. */ + system_variable_hash_version++; return result; } @@ -623,6 +627,16 @@ static int show_cmp(SHOW_VAR *a, SHOW_VAR *b) } +/* + Number of records in the system_variable_hash. + Requires lock on LOCK_system_variables_hash. +*/ +ulong get_system_variable_hash_records(void) +{ + return system_variable_hash.records; +} + + /** Constructs an array of system variables for display to the user. @@ -773,7 +787,8 @@ int set_var::check(THD *thd) my_error(err, MYF(0), var->name.str); return -1; } - if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))) + if (type == OPT_GLOBAL && + check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE)) return 1; /* value is a NULL pointer if we are using SET ... = DEFAULT */ if (!value) @@ -810,7 +825,8 @@ int set_var::light_check(THD *thd) my_error(err, MYF(0), var->name.str); return -1; } - if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) + if (type == OPT_GLOBAL && + check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE)) return 1; if (value && value->fix_fields_if_needed_for_scalar(thd, &value)) @@ -1377,7 +1393,7 @@ resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len, if (temp_copy) res= (plugin_ref *)thd->calloc((count+1)*sizeof(*res)); else - res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); + res= (plugin_ref *)my_malloc(PSI_INSTRUMENT_ME, (count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME)); if (!res) { my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res))); @@ -1428,7 +1444,7 @@ copy_engine_list(plugin_ref *list) for (p= list, count= 0; *p; ++p, ++count) ; - p= (plugin_ref *)my_malloc((count+1)*sizeof(*p), MYF(0)); + p= (plugin_ref *)my_malloc(PSI_INSTRUMENT_ME, (count+1)*sizeof(*p), MYF(0)); if (!p) { my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p))); @@ -1503,3 +1519,13 @@ pretty_print_engine_list(THD *thd, plugin_ref *list) *pos= '\0'; return buf; } + +/* + Current version of the system_variable_hash. + Requires lock on LOCK_system_variables_hash. +*/ +ulonglong get_system_variable_hash_version(void) +{ + return system_variable_hash_version; +} + diff --git a/sql/set_var.h b/sql/set_var.h index c4a29968818..075339c4f38 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -404,6 +404,8 @@ extern SHOW_COMP_OPTION have_openssl; /* Prototypes for helper functions */ +ulong get_system_variable_hash_records(void); +ulonglong get_system_variable_hash_version(void); SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type); int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index aa740ba5248..afa9d72f2d8 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7944,6 +7944,9 @@ ER_WARN_HISTORY_ROW_START_TIME ER_PART_STARTS_BEYOND_INTERVAL eng "%`s: STARTS is later than query time, first history partition may exceed INTERVAL value" ER_GALERA_REPLICATION_NOT_SUPPORTED - eng "DDL-statement is forbidden as table storage engine does not support Galera replication" + eng "DDL-statement is forbidden as table storage engine does not support Galera replication" +ER_LOAD_INFILE_CAPABILITY_DISABLED + eng "The used command is not allowed because the MariaDB server or client has disabled the local infile capability" + rum "Comanda folosită nu este permisă deoarece clientul sau serverul MariaDB a dezactivat această capabilitate" ER_NO_SECURE_TRANSPORTS_CONFIGURED eng "No secure transports are configured, unable to set --require_secure_transport=ON" diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 51b9d7a2c51..cbf58bb6e57 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -42,9 +42,6 @@ static volatile sig_atomic_t segfaulted= 0; extern ulong max_used_connections; extern volatile sig_atomic_t calling_initgroups; -#ifdef HAVE_NPTL -extern volatile sig_atomic_t ld_assume_kernel_is_set; -#endif extern const char *optimizer_switch_names[]; @@ -296,21 +293,6 @@ extern "C" sig_handler handle_fatal_signal(int sig) } #endif -#ifdef HAVE_NPTL - if (thd_lib_detected == THD_LIB_LT && !ld_assume_kernel_is_set) - { - my_safe_printf_stderr("%s", - "You are running a statically-linked LinuxThreads binary on an NPTL\n" - "system. This can result in crashes on some distributions due to " - "LT/NPTL conflicts.\n" - "You should either build a dynamically-linked binary, " - "or force LinuxThreads\n" - "to be used with the LD_ASSUME_KERNEL environment variable.\n" - "Please consult the documentation for your distribution " - "on how to do that.\n"); - } -#endif - if (locked_in_memory) { my_safe_printf_stderr("%s", "\n" diff --git a/sql/slave.cc b/sql/slave.cc index 87c1cf6cb77..aba10b8bd6e 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -57,6 +57,9 @@ #include "wsrep_trans_observer.h" #endif +class Master_info_index; +Master_info_index *master_info_index; + #ifdef HAVE_REPLICATION #include "rpl_tblmap.h" @@ -81,7 +84,6 @@ char slave_transaction_retry_error_names[SHOW_VAR_FUNC_BUFF_SIZE]; char* slave_load_tmpdir = 0; Master_info *active_mi= 0; -Master_info_index *master_info_index; my_bool replicate_same_server_id; ulonglong relay_log_space_limit = 0; ulonglong opt_read_binlog_speed_limit = 0; @@ -488,6 +490,7 @@ handle_slave_background(void *arg __attribute__((unused))) #ifdef WITH_WSREP thd->variables.wsrep_on= 0; #endif + thd->set_psi(PSI_CALL_get_thread()); thd_proc_info(thd, "Loading slave GTID position from table"); if (rpl_load_gtid_slave_state(thd)) @@ -583,7 +586,7 @@ slave_background_kill_request(THD *to_kill) if (to_kill->rgi_slave->killed_for_retry) return; // Already deadlock killed. slave_background_kill_t *p= - (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME)); + (slave_background_kill_t *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*p), MYF(MY_WME)); if (p) { p->to_kill= to_kill; @@ -611,7 +614,7 @@ slave_background_gtid_pos_create_request( if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE) return; - p= (slave_background_gtid_pos_create_t *)my_malloc(sizeof(*p), MYF(MY_WME)); + p= (slave_background_gtid_pos_create_t *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*p), MYF(MY_WME)); if (!p) return; mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state); @@ -1662,7 +1665,7 @@ bool Sql_cmd_show_slave_status::execute(THD *thd) bool res= true; /* Accept one of two privileges */ - if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_SLAVE_STATUS)) goto error; if (is_show_all_slaves_stat()) { @@ -1809,7 +1812,8 @@ int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f) (decimal size + space) - 1 + `\n' + '\0' */ size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1; - buf_act= (char*) my_malloc(max_size, MYF(MY_WME)); + buf_act= (char*) my_malloc(key_memory_Rpl_info_file_buffer, max_size, + MYF(MY_WME)); memcpy(buf_act, buf, read_size); snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size); if (snd_size == 0 || @@ -4727,6 +4731,8 @@ pthread_handler_t handle_slave_io(void *arg) THD_CHECK_SENTRY(thd); mi->io_thd = thd; + thd->set_psi(PSI_CALL_get_thread()); + pthread_detach_this_thread(); thd->thread_stack= (char*) &thd; // remember where our stack is mi->clear_error(); @@ -5365,6 +5371,8 @@ pthread_handler_t handle_slave_sql(void *arg) executing SQL queries too. */ serial_rgi->thd= rli->sql_driver_thd= thd; + + thd->set_psi(PSI_CALL_get_thread()); /* Inform waiting threads that slave has started */ rli->slave_run_id++; @@ -6035,7 +6043,8 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf, */ if ((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) { - if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME))))) + if (unlikely(!(tmp_buf=(char*)my_malloc(key_memory_binlog_ver_1_event, + event_len+1,MYF(MY_WME))))) { mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL, ER(ER_SLAVE_FATAL_ERROR), "Memory allocation failed"); diff --git a/sql/sp.cc b/sql/sp.cc index ae413fcf615..157ddeb63c6 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -28,12 +28,12 @@ // mysql_change_db, check_db_dir_existence, // load_db_opt_by_name #include "sql_table.h" // write_bin_log -#include "sql_acl.h" // SUPER_ACL #include "sp_head.h" #include "sp_cache.h" #include "lock.h" // lock_object_name #include <my_user.h> +#include "mysql/psi/mysql_sp.h" sp_cache **Sp_handler_procedure::get_cache(THD *thd) const { @@ -718,7 +718,7 @@ Sp_handler::db_find_routine(THD *thd, table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root, ¶ms); - if (type() != TYPE_ENUM_FUNCTION) + if (type() != SP_TYPE_FUNCTION) returns= empty_clex_str; else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root, &returns)) @@ -866,6 +866,8 @@ static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode, thd->spcont= old_spcont; thd->variables.sql_mode= old_sql_mode; thd->variables.select_limit= old_select_limit; + if (sp != NULL) + sp->init_psi_share(); return sp; } @@ -1001,7 +1003,7 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name, (*sphp)->set_creation_ctx(creation_ctx); (*sphp)->optimize(); - if (type() == TYPE_ENUM_PACKAGE_BODY) + if (type() == SP_TYPE_PACKAGE_BODY) { sp_package *package= (*sphp)->get_package(); List_iterator<LEX> it(package->m_routine_implementations); @@ -1104,6 +1106,9 @@ Sp_handler::sp_drop_routine_internal(THD *thd, DBUG_ASSERT(spc); if ((sp= sp_cache_lookup(spc, name))) sp_cache_flush_obsolete(spc, &sp); + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(type(), name->m_db.str, static_cast<uint>(name->m_db.length), + name->m_name.str, static_cast<uint>(name->m_name.length)); DBUG_RETURN(SP_OK); } @@ -1231,17 +1236,17 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const if (lex->create_info.or_replace()) { switch (type()) { - case TYPE_ENUM_PACKAGE: + case SP_TYPE_PACKAGE: // Drop together with its PACKAGE BODY mysql.proc record ret= sp_handler_package_spec.sp_find_and_drop_routine(thd, table, sp); break; - case TYPE_ENUM_PACKAGE_BODY: - case TYPE_ENUM_FUNCTION: - case TYPE_ENUM_PROCEDURE: + case SP_TYPE_PACKAGE_BODY: + case SP_TYPE_FUNCTION: + case SP_TYPE_PROCEDURE: ret= sp_drop_routine_internal(thd, sp, table); break; - case TYPE_ENUM_TRIGGER: - case TYPE_ENUM_PROXY: + case SP_TYPE_TRIGGER: + case SP_TYPE_EVENT: DBUG_ASSERT(0); ret= SP_OK; } @@ -1258,7 +1263,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const ret= FALSE; // Setting retstr as it is used for logging. - if (type() == TYPE_ENUM_FUNCTION) + if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); returns= retstr.lex_cstring(); @@ -1341,7 +1346,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> store(sp->m_params, system_charset_info); - if (type() == TYPE_ENUM_FUNCTION) + if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); returns= retstr.lex_cstring(); @@ -1373,7 +1378,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const store(sp->comment(), system_charset_info); } - if (type() == TYPE_ENUM_FUNCTION && + if (type() == SP_TYPE_FUNCTION && !trust_function_creators && mysql_bin_log.is_open()) { if (!sp->detistic()) @@ -1392,7 +1397,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const goto done; } } - if (!(thd->security_ctx->master_access & SUPER_ACL)) + if (!(thd->security_ctx->master_access & PRIV_LOG_BIN_TRUSTED_SP_CREATOR)) { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,MYF(0)); goto done; @@ -1625,7 +1630,7 @@ Sp_handler::sp_update_routine(THD *thd, const Database_qualified_name *name, if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK) { - if (type() == TYPE_ENUM_FUNCTION && ! trust_function_creators && + if (type() == SP_TYPE_FUNCTION && ! trust_function_creators && mysql_bin_log.is_open() && (chistics->daccess == SP_CONTAINS_SQL || chistics->daccess == SP_MODIFIES_SQL_DATA)) @@ -1771,11 +1776,11 @@ bool lock_db_routines(THD *thd, const char *db) longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int(); MDL_request *mdl_request= new (thd->mem_root) MDL_request; - const Sp_handler *sph= Sp_handler::handler((stored_procedure_type) + const Sp_handler *sph= Sp_handler::handler((enum_sp_type) sp_type); if (!sph) sph= &sp_handler_procedure; - mdl_request->init(sph->get_mdl_type(), db, sp_name, + MDL_REQUEST_INIT(mdl_request, sph->get_mdl_type(), db, sp_name, MDL_EXCLUSIVE, MDL_TRANSACTION); mdl_requests.push_front(mdl_request); } while (! (nxtres= table->file->ha_index_next_same(table->record[0], keybuf, key_len))); @@ -1814,6 +1819,8 @@ sp_drop_db_routines(THD *thd, const char *db) uint key_len; MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); uchar keybuf[MAX_KEY_LENGTH]; + size_t db_length= strlen(db); + Sql_mode_instant_remove smir(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); // see below DBUG_ENTER("sp_drop_db_routines"); DBUG_PRINT("enter", ("db: %s", db)); @@ -1821,7 +1828,7 @@ sp_drop_db_routines(THD *thd, const char *db) if (!(table= open_proc_table_for_update(thd))) goto err; - table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info); + table->field[MYSQL_PROC_FIELD_DB]->store(db, db_length, system_charset_info); key_len= table->key_info->key_part[0].store_length; table->field[MYSQL_PROC_FIELD_DB]->get_key_image(keybuf, key_len, Field::itRAW); @@ -1840,7 +1847,18 @@ sp_drop_db_routines(THD *thd, const char *db) do { if (! table->file->ha_delete_row(table->record[0])) + { deleted= TRUE; /* We deleted something */ +#ifdef HAVE_PSI_SP_INTERFACE + String buf; + // the following assumes MODE_PAD_CHAR_TO_FULL_LENGTH being *unset* + String *name= table->field[MYSQL_PROC_FIELD_NAME]->val_str(&buf); + + enum_sp_type sp_type= (enum_sp_type) table->field[MYSQL_PROC_MYSQL_TYPE]->ptr[0]; + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(sp_type, db, static_cast<uint>(db_length), name->ptr(), name->length()); +#endif + } else { ret= SP_DELETE_ROW_FAILED; @@ -2014,7 +2032,7 @@ Sp_handler::sp_clone_and_link_routine(THD *thd, DBUG_RETURN(0); } - if (type() == TYPE_ENUM_FUNCTION) + if (type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); returns= retstr.lex_cstring(); @@ -2282,7 +2300,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, const Sp_handler *handler, TABLE_LIST *belong_to_view) { - my_hash_init_opt(&prelocking_ctx->sroutines, system_charset_info, + my_hash_init_opt(PSI_INSTRUMENT_ME, &prelocking_ctx->sroutines, system_charset_info, Query_tables_list::START_SROUTINES_HASH_SIZE, 0, 0, sp_sroutine_key, 0, 0); @@ -2292,7 +2310,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry)); if (unlikely(!rn)) // OOM. Error will be reported using fatal_error(). return FALSE; - rn->mdl_request.init(key, MDL_SHARED, MDL_TRANSACTION); + MDL_REQUEST_INIT_BY_KEY(&rn->mdl_request, key, MDL_SHARED, MDL_TRANSACTION); if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn)) return FALSE; prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next); @@ -2362,7 +2380,7 @@ is_package_public_routine(THD *thd, const LEX_CSTRING &db, const LEX_CSTRING &package, const LEX_CSTRING &routine, - stored_procedure_type type) + enum_sp_type type) { sp_head *sp= NULL; Database_qualified_name tmp(db, package); @@ -2396,7 +2414,7 @@ is_package_public_routine_quick(THD *thd, const LEX_CSTRING &db, const LEX_CSTRING &pkgname, const LEX_CSTRING &name, - stored_procedure_type type) + enum_sp_type type) { Database_qualified_name tmp(db, pkgname); sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, &tmp); @@ -2415,7 +2433,7 @@ static bool is_package_body_routine(THD *thd, sp_package *pkg, const LEX_CSTRING &name1, const LEX_CSTRING &name2, - stored_procedure_type type) + enum_sp_type type) { return Sp_handler::eq_routine_name(pkg->m_name, name1) && (pkg->m_routine_declarations.find(name2, type) || @@ -2843,7 +2861,7 @@ Sp_handler::sp_cache_package_routine(THD *thd, bool lookup_only, sp_head **sp) const { DBUG_ENTER("sp_cache_package_routine"); - DBUG_ASSERT(type() == TYPE_ENUM_FUNCTION || type() == TYPE_ENUM_PROCEDURE); + DBUG_ASSERT(type() == SP_TYPE_FUNCTION || type() == SP_TYPE_PROCEDURE); sp_name pkgname(&name->m_db, &pkgname_cstr, false); sp_head *ph= NULL; int ret= sp_handler_package_body.sp_cache_routine(thd, &pkgname, @@ -2942,7 +2960,7 @@ Sp_handler::show_create_sp(THD *thd, String *buf, buf->append('('); buf->append(¶ms); buf->append(')'); - if (type() == TYPE_ENUM_FUNCTION) + if (type() == SP_TYPE_FUNCTION) { if (sql_mode & MODE_ORACLE) buf->append(STRING_WITH_LEN(" RETURN ")); @@ -47,18 +47,18 @@ template <typename T> class SQL_I_List; /* Values for the type enum. This reflects the order of the enum declaration in the CREATE TABLE command. + See also storage/perfschema/my_thread.h */ -enum stored_procedure_type +enum enum_sp_type { - TYPE_ENUM_FUNCTION=1, - TYPE_ENUM_PROCEDURE=2, - TYPE_ENUM_PACKAGE=3, - TYPE_ENUM_PACKAGE_BODY=4, - TYPE_ENUM_TRIGGER=5, - TYPE_ENUM_PROXY=6 + SP_TYPE_FUNCTION=1, + SP_TYPE_PROCEDURE=2, + SP_TYPE_PACKAGE=3, + SP_TYPE_PACKAGE_BODY=4, + SP_TYPE_TRIGGER=5, + SP_TYPE_EVENT=6, }; - class Sp_handler { bool sp_resolve_package_routine_explicit(THD *thd, @@ -121,13 +121,13 @@ public: // TODO: make it private or protected public: virtual ~Sp_handler() {} static const Sp_handler *handler(enum enum_sql_command cmd); - static const Sp_handler *handler(stored_procedure_type type); + static const Sp_handler *handler(enum_sp_type type); static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns); /* Return a handler only those SP objects that store definitions in the mysql.proc system table */ - static const Sp_handler *handler_mysql_proc(stored_procedure_type type) + static const Sp_handler *handler_mysql_proc(enum_sp_type type) { const Sp_handler *sph= handler(type); return sph ? sph->sp_handler_mysql_proc() : NULL; @@ -154,7 +154,7 @@ public: { return this; } - virtual stored_procedure_type type() const= 0; + virtual enum_sp_type type() const= 0; virtual LEX_CSTRING type_lex_cstring() const= 0; virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const { @@ -249,7 +249,7 @@ public: class Sp_handler_procedure: public Sp_handler { public: - stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; } + enum_sp_type type() const { return SP_TYPE_PROCEDURE; } LEX_CSTRING type_lex_cstring() const { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("PROCEDURE")}; @@ -299,7 +299,7 @@ public: class Sp_handler_function: public Sp_handler { public: - stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; } + enum_sp_type type() const { return SP_TYPE_FUNCTION; } LEX_CSTRING type_lex_cstring() const { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("FUNCTION")}; @@ -368,7 +368,7 @@ public: // TODO: make it private or protected const Database_qualified_name *name) const; public: - stored_procedure_type type() const { return TYPE_ENUM_PACKAGE; } + enum_sp_type type() const { return SP_TYPE_PACKAGE; } LEX_CSTRING type_lex_cstring() const { static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE")}; @@ -401,7 +401,7 @@ public: class Sp_handler_package_body: public Sp_handler_package { public: - stored_procedure_type type() const { return TYPE_ENUM_PACKAGE_BODY; } + enum_sp_type type() const { return SP_TYPE_PACKAGE_BODY; } LEX_CSTRING type_lex_cstring() const { static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE BODY")}; @@ -434,7 +434,7 @@ public: class Sp_handler_trigger: public Sp_handler { public: - stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; } + enum_sp_type type() const { return SP_TYPE_TRIGGER; } LEX_CSTRING type_lex_cstring() const { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("TRIGGER")}; @@ -493,20 +493,20 @@ inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd) } -inline const Sp_handler *Sp_handler::handler(stored_procedure_type type) +inline const Sp_handler *Sp_handler::handler(enum_sp_type type) { switch (type) { - case TYPE_ENUM_PROCEDURE: + case SP_TYPE_PROCEDURE: return &sp_handler_procedure; - case TYPE_ENUM_FUNCTION: + case SP_TYPE_FUNCTION: return &sp_handler_function; - case TYPE_ENUM_PACKAGE: + case SP_TYPE_PACKAGE: return &sp_handler_package_spec; - case TYPE_ENUM_PACKAGE_BODY: + case SP_TYPE_PACKAGE_BODY: return &sp_handler_package_body; - case TYPE_ENUM_TRIGGER: + case SP_TYPE_TRIGGER: return &sp_handler_trigger; - case TYPE_ENUM_PROXY: + case SP_TYPE_EVENT: break; } return NULL; diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index e4ffbdcb155..a8659cc121f 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -302,7 +302,7 @@ sp_cache::~sp_cache() void sp_cache::init() { - my_hash_init(&m_hashtable, system_charset_info, 0, 0, 0, + my_hash_init(key_memory_sp_cache, &m_hashtable, system_charset_info, 0, 0, 0, hash_get_key_for_sp_head, hash_free_sp_head, 0); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c15465f105e..b63cf79dd7e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -23,7 +23,6 @@ #include "probes_mysql.h" #include "sql_show.h" // append_identifier #include "sql_db.h" // mysql_opt_change_db, mysql_change_db -#include "sql_acl.h" // *_ACL #include "sql_array.h" // Dynamic_array #include "log_event.h" // Query_log_event #include "sql_derived.h" // mysql_handle_derived @@ -56,8 +55,51 @@ #define SP_INSTR_UINT_MAXLEN 8 #define SP_STMT_PRINT_MAXLEN 40 - #include <my_user.h> +#include "mysql/psi/mysql_statement.h" +#include "mysql/psi/mysql_sp.h" + +#ifdef HAVE_PSI_INTERFACE +void init_sp_psi_keys() +{ + const char *category= "sp"; + const int num __attribute__((unused)) = __LINE__ + 3; + + PSI_server->register_statement(category, & sp_instr_stmt::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_set::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_set_trigger_field::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_jump::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_jump_if_not::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_freturn::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_preturn::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_hpush_jump::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_hpop::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_hreturn::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_cpush::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_cpop::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_copen::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_cclose::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_cfetch::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_agg_cfetch::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_cursor_copy_struct::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_error::psi_info, 1); + PSI_server->register_statement(category, & sp_instr_set_case_expr::psi_info, 1); + + DBUG_ASSERT(SP_PSI_STATEMENT_INFO_COUNT == __LINE__ - num); +} +#endif + +#ifdef HAVE_PSI_SP_INTERFACE +#define MYSQL_RUN_SP(SP,CODE) \ + do { \ + PSI_sp_locker_state psi_state; \ + PSI_sp_locker *locker= MYSQL_START_SP(&psi_state, (SP)->m_sp_share); \ + CODE; \ + MYSQL_END_SP(locker); \ + } while(0) +#else +#define MYSQL_RUN_SP(SP, CODE) do { CODE; } while(0) +#endif extern "C" uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first); @@ -188,7 +230,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_ENGINE_MUTEX: case SQLCOM_SHOW_EVENTS: case SQLCOM_SHOW_KEYS: - case SQLCOM_SHOW_MASTER_STAT: + case SQLCOM_SHOW_BINLOG_STAT: case SQLCOM_SHOW_OPEN_TABLES: case SQLCOM_SHOW_PRIVILEGES: case SQLCOM_SHOW_PROCESSLIST: @@ -455,8 +497,8 @@ sp_head *sp_head::create(sp_package *parent, const Sp_handler *handler, enum_sp_aggregate_type agg_type) { MEM_ROOT own_root; - init_sql_alloc(&own_root, "sp_head", MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC, - MYF(0)); + init_sql_alloc(key_memory_sp_head_main_root, &own_root, MEM_ROOT_BLOCK_SIZE, + MEM_ROOT_PREALLOC, MYF(0)); sp_head *sp; if (!(sp= new (&own_root) sp_head(&own_root, parent, handler, agg_type))) free_root(&own_root, MYF(0)); @@ -537,11 +579,12 @@ sp_head::sp_head(MEM_ROOT *mem_root_arg, sp_package *parent, m_backpatch_goto.empty(); m_cont_backpatch.empty(); m_lex.empty(); - my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8, MYF(0)); - my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); - my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, - 0, 0); - m_security_ctx.init(); + my_init_dynamic_array(key_memory_sp_head_main_root, &m_instr, + sizeof(sp_instr *), 16, 8, MYF(0)); + my_hash_init(key_memory_sp_head_main_root, &m_sptabs, system_charset_info, 0, + 0, 0, sp_table_key, 0, 0); + my_hash_init(key_memory_sp_head_main_root, &m_sroutines, system_charset_info, + 0, 0, 0, sp_sroutine_key, 0, 0); DBUG_VOID_RETURN; } @@ -551,7 +594,7 @@ sp_package *sp_package::create(LEX *top_level_lex, const sp_name *name, const Sp_handler *sph) { MEM_ROOT own_root; - init_sql_alloc(&own_root, "sp_package", MEM_ROOT_BLOCK_SIZE, + init_sql_alloc(key_memory_sp_head_main_root, &own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC, MYF(0)); sp_package *sp; if (!(sp= new (&own_root) sp_package(&own_root, top_level_lex, name, sph))) @@ -604,7 +647,7 @@ bool sp_head::eq_routine_spec(const sp_head *sp) const bool sp_package::validate_after_parser(THD *thd) { - if (m_handler->type() != TYPE_ENUM_PACKAGE_BODY) + if (m_handler->type() != SP_TYPE_PACKAGE_BODY) return false; sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, this); sp_package *spec= sp ? sp->get_package() : NULL; @@ -683,7 +726,7 @@ bool sp_package::validate_private_routines(THD *thd) LEX *sp_package::LexList::find(const LEX_CSTRING &name, - stored_procedure_type type) + enum_sp_type type) { List_iterator<LEX> it(*this); for (LEX *lex; (lex= it++); ) @@ -706,7 +749,7 @@ LEX *sp_package::LexList::find(const LEX_CSTRING &name, LEX *sp_package::LexList::find_qualified(const LEX_CSTRING &name, - stored_procedure_type type) + enum_sp_type type) { List_iterator<LEX> it(*this); for (LEX *lex; (lex= it++); ) @@ -720,6 +763,17 @@ LEX *sp_package::LexList::find_qualified(const LEX_CSTRING &name, } +void sp_package::init_psi_share() +{ + List_iterator<LEX> it(m_routine_implementations); + for (LEX *lex; (lex= it++); ) + { + DBUG_ASSERT(lex->sphead); + lex->sphead->init_psi_share(); + } + sp_head::init_psi_share(); +} + void sp_head::init(LEX *lex) { @@ -755,6 +809,13 @@ sp_head::init_sp_name(const sp_name *spname) DBUG_VOID_RETURN; } +void +sp_head::init_psi_share() +{ + m_sp_share= MYSQL_GET_SP_SHARE(m_handler->type(), m_db.str, static_cast<uint>(m_db.length), + m_name.str, static_cast<uint>(m_name.length)); +} + void sp_head::set_body_start(THD *thd, const char *begin_ptr) @@ -1038,7 +1099,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) { DBUG_ENTER("subst_spvars"); - Dynamic_array<Rewritable_query_parameter*> rewritables; + Dynamic_array<Rewritable_query_parameter*> rewritables(PSI_INSTRUMENT_MEM); char *pbuf; StringBuffer<512> qbuf; Copy_query_with_rewrite acc(thd, query_str->str, query_str->length, &qbuf); @@ -1170,7 +1231,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) opt_trace_disable_if_no_security_context_access(thd); /* init per-instruction memroot */ - init_sql_alloc(&execute_mem_root, "per_instruction_memroot", + init_sql_alloc(key_memory_sp_head_execute_root, &execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); DBUG_ASSERT(!(m_flags & IS_INVOKED)); @@ -1357,8 +1418,24 @@ sp_head::execute(THD *thd, bool merge_da_on_success) WSREP_DEBUG("assigned new next trx ID for SP, trx id: %" PRIu64, thd->wsrep_next_trx_id()); } #endif /* WITH_WSREP */ + +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_statement_locker_state state; + PSI_statement_locker *parent_locker; + PSI_statement_info *psi_info = i->get_psi_info(); + + parent_locker= thd->m_statement_psi; + thd->m_statement_psi= MYSQL_START_STATEMENT(& state, psi_info->m_key, + thd->db.str, thd->db.length, thd->charset(), m_sp_share); +#endif + err_status= i->execute(thd, &ip); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= parent_locker; +#endif + #ifdef WITH_WSREP if (WSREP(thd)) { @@ -1815,8 +1892,8 @@ sp_head::execute_trigger(THD *thd, TODO: we should create sp_rcontext once per command and reuse it on subsequent executions of a trigger. */ - init_sql_alloc(&call_mem_root, "execute_trigger", MEM_ROOT_BLOCK_SIZE, 0, - MYF(0)); + init_sql_alloc(key_memory_sp_head_call_root, + &call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); thd->set_n_backup_active_arena(&call_arena, &backup_arena); Row_definition_list defs; @@ -1829,7 +1906,7 @@ sp_head::execute_trigger(THD *thd, thd->spcont= nctx; - err_status= execute(thd, FALSE); + MYSQL_RUN_SP(this, err_status= execute(thd, FALSE)); err_with_cleanup: thd->restore_active_arena(&call_arena, &backup_arena); @@ -2079,7 +2156,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, */ thd->set_n_backup_active_arena(call_arena, &backup_arena); - err_status= execute(thd, TRUE); + MYSQL_RUN_SP(this, err_status= execute(thd, TRUE)); thd->restore_active_arena(call_arena, &backup_arena); @@ -2360,11 +2437,9 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) #endif opt_trace_disable_if_no_stored_proc_func_access(thd, this); + if (!err_status) - { - err_status= execute(thd, TRUE); - DBUG_PRINT("info", ("execute returned %d", (int) err_status)); - } + MYSQL_RUN_SP(this, err_status= execute(thd, TRUE)); if (save_log_general) thd->variables.option_bits &= ~OPTION_LOG_OFF; @@ -3444,7 +3519,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->mdl_context.release_statement_locks(); } } - //TODO: why is this here if log_slow_query is in sp_instr_stmt_execute? + //TODO: why is this here if log_slow_query is in sp_instr_stmt::execute? delete_explain_query(m_lex); if (m_lex->query_tables_own_last) @@ -3553,6 +3628,9 @@ int sp_instr::exec_core(THD *thd, uint *nextp) sp_instr_stmt class functions */ +PSI_statement_info sp_instr_stmt::psi_info= +{ 0, "stmt", 0}; + int sp_instr_stmt::execute(THD *thd, uint *nextp) { @@ -3563,6 +3641,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, m_query.str, static_cast<uint>(m_query.length)); + #if defined(ENABLED_PROFILING) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); @@ -3689,6 +3769,9 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp) sp_instr_set class functions */ +PSI_statement_info sp_instr_set::psi_info= +{ 0, "set", 0}; + int sp_instr_set::execute(THD *thd, uint *nextp) { @@ -3839,6 +3922,9 @@ sp_instr_set_row_field_by_name::print(String *str) sp_instr_set_trigger_field class functions */ +PSI_statement_info sp_instr_set_trigger_field::psi_info= +{ 0, "set_trigger_field", 0}; + int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { @@ -3882,6 +3968,9 @@ uint sp_instr_opt_meta::get_cont_dest() const sp_instr_jump class functions */ +PSI_statement_info sp_instr_jump::psi_info= +{ 0, "jump", 0}; + int sp_instr_jump::execute(THD *thd, uint *nextp) { @@ -3947,6 +4036,9 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) sp_instr_jump_if_not class functions */ +PSI_statement_info sp_instr_jump_if_not::psi_info= +{ 0, "jump_if_not", 0}; + int sp_instr_jump_if_not::execute(THD *thd, uint *nextp) { @@ -4042,6 +4134,9 @@ sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp) sp_instr_freturn class functions */ +PSI_statement_info sp_instr_freturn::psi_info= +{ 0, "freturn", 0}; + int sp_instr_freturn::execute(THD *thd, uint *nextp) { @@ -4106,9 +4201,33 @@ sp_instr_freturn::print(String *str) } /* + sp_instr_preturn class functions +*/ + +PSI_statement_info sp_instr_preturn::psi_info= +{ 0, "preturn", 0}; + +int +sp_instr_preturn::execute(THD *thd, uint *nextp) +{ + DBUG_ENTER("sp_instr_preturn::execute"); + *nextp= UINT_MAX; + DBUG_RETURN(0); +} + +void +sp_instr_preturn::print(String *str) +{ + str->append(STRING_WITH_LEN("preturn")); +} + +/* sp_instr_hpush_jump class functions */ +PSI_statement_info sp_instr_hpush_jump::psi_info= +{ 0, "hpush_jump", 0}; + int sp_instr_hpush_jump::execute(THD *thd, uint *nextp) { @@ -4185,6 +4304,9 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads) sp_instr_hpop class functions */ +PSI_statement_info sp_instr_hpop::psi_info= +{ 0, "hpop", 0}; + int sp_instr_hpop::execute(THD *thd, uint *nextp) { @@ -4209,6 +4331,9 @@ sp_instr_hpop::print(String *str) sp_instr_hreturn class functions */ +PSI_statement_info sp_instr_hreturn::psi_info= +{ 0, "hreturn", 0}; + int sp_instr_hreturn::execute(THD *thd, uint *nextp) { @@ -4268,6 +4393,9 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) sp_instr_cpush class functions */ +PSI_statement_info sp_instr_cpush::psi_info= +{ 0, "cpush", 0}; + int sp_instr_cpush::execute(THD *thd, uint *nextp) { @@ -4309,6 +4437,9 @@ sp_instr_cpush::print(String *str) sp_instr_cpop class functions */ +PSI_statement_info sp_instr_cpop::psi_info= +{ 0, "cpop", 0}; + int sp_instr_cpop::execute(THD *thd, uint *nextp) { @@ -4339,6 +4470,9 @@ sp_instr_cpop::print(String *str) Assert that we either have an error or a cursor */ +PSI_statement_info sp_instr_copen::psi_info= +{ 0, "copen", 0}; + int sp_instr_copen::execute(THD *thd, uint *nextp) { @@ -4397,6 +4531,9 @@ sp_instr_copen::print(String *str) sp_instr_cclose class functions */ +PSI_statement_info sp_instr_cclose::psi_info= +{ 0, "cclose", 0}; + int sp_instr_cclose::execute(THD *thd, uint *nextp) { @@ -4439,6 +4576,9 @@ sp_instr_cclose::print(String *str) sp_instr_cfetch class functions */ +PSI_statement_info sp_instr_cfetch::psi_info= +{ 0, "cfetch", 0}; + int sp_instr_cfetch::execute(THD *thd, uint *nextp) { @@ -4486,6 +4626,13 @@ sp_instr_cfetch::print(String *str) } } +/* + sp_instr_agg_cfetch class functions +*/ + +PSI_statement_info sp_instr_agg_cfetch::psi_info= +{ 0, "agg_cfetch", 0}; + int sp_instr_agg_cfetch::execute(THD *thd, uint *nextp) { @@ -4538,6 +4685,9 @@ sp_instr_agg_cfetch::print(String *str) - copies the cursor structure to the associated %ROWTYPE variable. */ +PSI_statement_info sp_instr_cursor_copy_struct::psi_info= +{ 0, "cursor_copy_struct", 0}; + int sp_instr_cursor_copy_struct::exec_core(THD *thd, uint *nextp) { @@ -4610,6 +4760,9 @@ sp_instr_cursor_copy_struct::print(String *str) sp_instr_error class functions */ +PSI_statement_info sp_instr_error::psi_info= +{ 0, "error", 0}; + int sp_instr_error::execute(THD *thd, uint *nextp) { @@ -4636,6 +4789,9 @@ sp_instr_error::print(String *str) sp_instr_set_case_expr class implementation **************************************************************************/ +PSI_statement_info sp_instr_set_case_expr::psi_info= +{ 0, "set_case_expr", 0}; + int sp_instr_set_case_expr::execute(THD *thd, uint *nextp) { @@ -4976,8 +5132,8 @@ sp_add_to_query_tables(THD *thd, LEX *lex, table->lock_type= locktype; table->select_lex= lex->current_select; table->cacheable_table= 1; - table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str, - mdl_type, MDL_TRANSACTION); + MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str, + table->table_name.str, mdl_type, MDL_TRANSACTION); lex->add_to_query_tables(table); return table; diff --git a/sql/sp_head.h b/sql/sp_head.h index 6cf4610c466..913be1aace7 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -47,6 +47,14 @@ class sp_instr; class sp_instr_opt_meta; class sp_instr_jump_if_not; +/** + Number of PSI_statement_info instruments + for internal stored programs statements. +*/ +#ifdef HAVE_PSI_INTERFACE +void init_sp_psi_keys(void); +#endif + /*************************************************************************/ /** @@ -174,6 +182,11 @@ public: const Sp_handler *m_handler; uint m_flags; // Boolean attributes of a stored routine + /** + Instrumentation interface for SP. + */ + PSI_sp_share *m_sp_share; + Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */ const char *m_tmp_query; ///< Temporary pointer to sub query string @@ -856,6 +869,8 @@ public: return NULL; } + virtual void init_psi_share(); + protected: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root @@ -931,9 +946,9 @@ public: public: LexList() { elements= 0; } // Find a package routine by a non qualified name - LEX *find(const LEX_CSTRING &name, stored_procedure_type type); + LEX *find(const LEX_CSTRING &name, enum_sp_type type); // Find a package routine by a package-qualified name, e.g. 'pkg.proc' - LEX *find_qualified(const LEX_CSTRING &name, stored_procedure_type type); + LEX *find_qualified(const LEX_CSTRING &name, enum_sp_type type); // Check if a routine with the given qualified name already exists bool check_dup_qualified(const LEX_CSTRING &name, const Sp_handler *sph) { @@ -990,6 +1005,7 @@ public: m_routine_implementations.push_back(lex, &main_mem_root); } sp_package *get_package() { return this; } + void init_psi_share(); bool is_invoked() const { /* @@ -1156,6 +1172,7 @@ public: { m_ip= dst; } + virtual PSI_statement_info* get_psi_info() = 0; }; // class sp_instr : public Sql_alloc @@ -1282,6 +1299,10 @@ private: sp_lex_keeper m_lex_keeper; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; + }; // class sp_instr_stmt : public sp_instr @@ -1316,6 +1337,10 @@ protected: uint m_offset; ///< Frame offset Item *m_value; sp_lex_keeper m_lex_keeper; + +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_set : public sp_instr @@ -1424,6 +1449,10 @@ private: Item_trigger_field *trigger_field; Item *value; sp_lex_keeper m_lex_keeper; + +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_trigger_field : public sp_instr @@ -1510,6 +1539,9 @@ public: m_dest= new_dest; } +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_jump : public sp_instr_opt_meta @@ -1561,6 +1593,9 @@ private: Item *m_expr; ///< The condition sp_lex_keeper m_lex_keeper; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_jump_if_not : public sp_instr_jump @@ -1578,17 +1613,9 @@ public: virtual ~sp_instr_preturn() {} - virtual int execute(THD *thd, uint *nextp) - { - DBUG_ENTER("sp_instr_preturn::execute"); - *nextp= UINT_MAX; - DBUG_RETURN(0); - } + virtual int execute(THD *thd, uint *nextp); - virtual void print(String *str) - { - str->append(STRING_WITH_LEN("preturn")); - } + virtual void print(String *str); virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) { @@ -1596,6 +1623,9 @@ public: return UINT_MAX; } +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_preturn : public sp_instr @@ -1633,6 +1663,9 @@ protected: const Type_handler *m_type_handler; sp_lex_keeper m_lex_keeper; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_freturn : public sp_instr @@ -1698,6 +1731,9 @@ private: // debug version only). It's used in print(). uint m_frame; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_hpush_jump : public sp_instr_jump @@ -1728,6 +1764,9 @@ private: uint m_count; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_hpop : public sp_instr @@ -1762,12 +1801,14 @@ private: uint m_frame; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_hreturn : public sp_instr_jump /** This is DECLARE CURSOR */ -class sp_instr_cpush : public sp_instr, - public sp_cursor +class sp_instr_cpush : public sp_instr, public sp_cursor { sp_instr_cpush(const sp_instr_cpush &); /**< Prevent use of these */ void operator=(sp_instr_cpush &); @@ -1796,6 +1837,9 @@ private: sp_lex_keeper m_lex_keeper; uint m_cursor; /**< Frame offset (for debugging) */ +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_cpush : public sp_instr @@ -1826,6 +1870,9 @@ private: uint m_count; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_cpop : public sp_instr @@ -1853,6 +1900,9 @@ private: uint m_cursor; ///< Stack index +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_copen : public sp_instr_stmt @@ -1880,6 +1930,10 @@ public: virtual int execute(THD *thd, uint *nextp); virtual int exec_core(THD *thd, uint *nextp); virtual void print(String *str); + +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; @@ -1905,6 +1959,9 @@ private: uint m_cursor; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_cclose : public sp_instr @@ -1939,6 +1996,9 @@ private: List<sp_variable> m_varlist; bool m_error_on_no_data; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_cfetch : public sp_instr /* @@ -1963,6 +2023,10 @@ public: virtual int execute(THD *thd, uint *nextp); virtual void print(String *str); + +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_agg_cfetch : public sp_instr @@ -1996,6 +2060,9 @@ private: int m_errcode; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_error : public sp_instr @@ -2035,6 +2102,9 @@ private: Item *m_case_expr; sp_lex_keeper m_lex_keeper; +public: + virtual PSI_statement_info* get_psi_info() { return & psi_info; } + static PSI_statement_info psi_info; }; // class sp_instr_set_case_expr : public sp_instr_opt_meta bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access); diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 01841bb57b7..848d1f0c655 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -96,6 +96,9 @@ sp_pcontext::sp_pcontext() : Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_parent(NULL), m_pboundary(0), + m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM), + m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM), + m_handlers(PSI_INSTRUMENT_MEM), m_children(PSI_INSTRUMENT_MEM), m_scope(REGULAR_SCOPE) { init(0, 0, 0); @@ -106,6 +109,9 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope) : Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_parent(prev), m_pboundary(0), + m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM), + m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM), + m_handlers(PSI_INSTRUMENT_MEM), m_children(PSI_INSTRUMENT_MEM), m_scope(scope) { init(prev->m_var_offset + prev->m_max_var_index, diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 17b4c83b7bc..c4c19dd39f6 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -74,6 +74,7 @@ sp_rcontext::sp_rcontext(const sp_head *owner, m_return_value_fld(return_value_fld), m_return_value_set(false), m_in_sub_stmt(in_sub_stmt), + m_handlers(PSI_INSTRUMENT_MEM), m_handler_call_stack(PSI_INSTRUMENT_MEM), m_ccount(0) { } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 45bb6ae89ad..4c9a523159d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -68,6 +68,15 @@ const uint max_hostname_length= 60; const uint max_dbname_length= 64; #endif +const char *safe_vio_type_name(Vio *vio) +{ + size_t unused; +#ifdef EMBEDDED_LIBRARY + if (!vio) return "Internal"; +#endif + return vio_type_name(vio_type(vio), &unused); +} + #include "sql_acl_getsort.ic" static LEX_CSTRING native_password_plugin_name= { @@ -645,7 +654,7 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, const char *username, #define ROLE_OPENED (1L << 3) static DYNAMIC_ARRAY acl_hosts, acl_users, acl_proxy_users; -static Dynamic_array<ACL_DB> acl_dbs(0U,50U); +static Dynamic_array<ACL_DB> acl_dbs(PSI_INSTRUMENT_MEM, 0U, 50U); typedef Dynamic_array<ACL_DB>::CMP_FUNC acl_dbs_cmp; static HASH acl_roles; /* @@ -992,7 +1001,7 @@ class User_table_tabular: public User_table { access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; if (access & FILE_ACL) - access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + access|= BINLOG_MONITOR_ACL | REPL_SLAVE_ACL | BINLOG_ADMIN_ACL ; if (access & PROCESS_ACL) access|= SUPER_ACL | EXECUTE_ACL; } @@ -1020,6 +1029,12 @@ class User_table_tabular: public User_table if (num_fields() <= 46 && (access & DELETE_ACL)) access|= DELETE_HISTORY_ACL; + if (access & SUPER_ACL) + access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS; + + if (access & REPL_SLAVE_ACL) + access|= REPL_MASTER_ADMIN_ACL; + return access & GLOBAL_ACLS; } @@ -1470,15 +1485,79 @@ class User_table_json: public User_table set_str_value("authentication_string", u.auth[i].auth_string.str, u.auth[i].auth_string.length); } + + void print_warning_bad_version_id(ulonglong version_id) const + { + sql_print_warning("'user' entry '%s@%s' has a wrong 'version_id' value %lld", + safe_str(get_user(current_thd->mem_root)), + safe_str(get_host(current_thd->mem_root)), + version_id); + } + + void print_warning_bad_access(ulonglong version_id, + privilege_t mask, + ulonglong access) const + { + sql_print_warning("'user' entry '%s@%s' " + "has a wrong 'access' value 0x%llx " + "(allowed mask is 0x%llx, version_id=%lld)", + safe_str(get_user(current_thd->mem_root)), + safe_str(get_host(current_thd->mem_root)), + access, mask, version_id); + } + + privilege_t adjust_access(ulonglong version_id, ulonglong access) const + { + privilege_t mask= ALL_KNOWN_ACL_100304; + ulonglong orig_access= access; + if (version_id >= 100502) + { + mask= ALL_KNOWN_ACL_100502; + } + else // 100501 or earlier + { + if (access & SUPER_ACL) + access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS; + + if (access & REPL_SLAVE_ACL) + access|= REPL_MASTER_ADMIN_ACL; + } + + if (orig_access & ~mask) + { + print_warning_bad_access(version_id, mask, orig_access); + return NO_ACL; + } + return access & ALL_KNOWN_ACL; + } + privilege_t get_access() const { + ulonglong version_id= (ulonglong) get_int_value("version_id"); + ulonglong access= (ulonglong) get_int_value("access"); + /* - when new privileges will be added, we'll start storing GLOBAL_ACLS - (or, for example, my_count_bits(GLOBAL_ACLS)) - in the json too, and it'll allow us to do privilege upgrades + Special case: + mysql_system_tables_data.sql populates "ALL PRIVILEGES" + for the super user this way: + {"access":18446744073709551615} */ - return get_access_value("access") & GLOBAL_ACLS; + if (access == (ulonglong) ~0) + return GLOBAL_ACLS; + + /* + Reject obviously bad (negative and too large) version_id values. + Also reject versions before 10.4.0 (when JSON table was added). + */ + if ((longlong) version_id < 0 || version_id > 999999 || + (version_id > 0 && version_id < 100400)) + { + print_warning_bad_version_id(version_id); + return NO_ACL; + } + return adjust_access(version_id, access) & GLOBAL_ACLS; } + void set_access(const privilege_t rights, bool revoke) const { privilege_t access= get_access(); @@ -1487,6 +1566,7 @@ class User_table_json: public User_table else access|= rights; set_int_value("access", (longlong) (access & GLOBAL_ACLS)); + set_int_value("version_id", (longlong) MYSQL_VERSION_ID); } const char *unsafe_str(const char *s) const { return s[0] ? s : NULL; } @@ -1607,10 +1687,6 @@ class User_table_json: public User_table const char *value_end= value_start + value_len; return my_strtoll10(value_start, (char**)&value_end, &err); } - privilege_t get_access_value(const char *key) const - { - return privilege_t(ALL_KNOWN_ACL & (ulonglong) get_int_value(key)); - } double get_double_value(const char *key) const { int err; @@ -2251,9 +2327,9 @@ bool acl_init(bool dont_read_acl_tables) bool return_val; DBUG_ENTER("acl_init"); - acl_cache= new Hash_filo<acl_entry>(ACL_CACHE_SIZE, 0, 0, + acl_cache= new Hash_filo<acl_entry>(key_memory_acl_cache, ACL_CACHE_SIZE, 0, 0, (my_hash_get_key) acl_entry_get_key, - (my_hash_free_key) free, + (my_hash_free_key) my_free, &my_charset_utf8mb3_bin); /* @@ -2328,7 +2404,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) grant_version++; /* Privileges updated */ const Host_table& host_table= tables.host_table(); - init_sql_alloc(&acl_memroot, "ACL", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_acl_mem, &acl_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); if (host_table.table_exists()) // "host" table may not exist (e.g. in MySQL 5.6.7+) { if (host_table.init_read_record(&read_record_info)) @@ -2405,7 +2481,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables) user.sort= get_magic_sort("hu", user.host.hostname, user.user.str); user.hostname_length= safe_strlen(user.host.hostname); - my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &user.role_grants, + sizeof(ACL_ROLE *), 0, 8, MYF(0)); user.account_locked= user_table.get_account_locked(); @@ -2423,7 +2500,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot); entry->role_grants = user.role_grants; - my_init_dynamic_array(&entry->parent_grantee, + my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee, sizeof(ACL_USER_BASE *), 0, 8, MYF(0)); my_hash_insert(&acl_roles, (uchar *)entry); @@ -2568,7 +2645,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) DBUG_RETURN(TRUE); MEM_ROOT temp_root; - init_alloc_root(&temp_root, "ACL_tmp", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_alloc_root(key_memory_acl_mem, &temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); while (!(read_record_info.read_record())) { char *hostname= safe_str(get_field(&temp_root, roles_mapping_table.host())); @@ -2687,15 +2764,16 @@ bool acl_reload(THD *thd) old_acl_roles_mappings= acl_roles_mappings; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; - my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); - my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); - acl_dbs.init(50, 100); - my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); - my_hash_init2(&acl_roles,50, &my_charset_utf8mb3_bin, + my_init_dynamic_array(key_memory_acl_mem, &acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); + acl_dbs.init(key_memory_acl_mem, 50, 100); + my_init_dynamic_array(key_memory_acl_mem, &acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); + my_hash_init2(key_memory_acl_mem, &acl_roles,50, &my_charset_utf8mb3_bin, 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0, (void (*)(void *))free_acl_role, 0); - my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8mb3_bin, 0, 0, 0, - (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); + my_hash_init2(key_memory_acl_mem, &acl_roles_mappings, 50, + &my_charset_utf8mb3_bin, 0, 0, 0, (my_hash_get_key) + acl_role_map_get_key, 0, 0, 0); old_mem= acl_memroot; delete_dynamic(&acl_wild_hosts); my_hash_free(&acl_check_hosts); @@ -3133,7 +3211,7 @@ ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo, sort= get_magic_sort("hu", host.hostname, user.str); password_last_changed= thd->query_start(); password_lifetime= -1; - my_init_dynamic_array(&role_grants, sizeof(ACL_USER *), 0, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &role_grants, sizeof(ACL_USER *), 0, 8, MYF(0)); } @@ -3218,9 +3296,10 @@ static void acl_insert_role(const char *rolename, privilege_t privileges) mysql_mutex_assert_owner(&acl_cache->lock); entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot); - my_init_dynamic_array(&entry->parent_grantee, + my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee, sizeof(ACL_USER_BASE *), 0, 8, MYF(0)); - my_init_dynamic_array(&entry->role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &entry->role_grants, + sizeof(ACL_ROLE *), 0, 8, MYF(0)); my_hash_insert(&acl_roles, (uchar *)entry); } @@ -3367,7 +3446,8 @@ privilege_t acl_get(const char *host, const char *ip, exit: /* Save entry in cache for quick retrieval */ if (!db_is_pattern && - (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length))) + (entry= (acl_entry*) my_malloc(key_memory_acl_cache, + sizeof(acl_entry)+key_length, MYF(MY_WME)))) { entry->access=(db_access & host_access); DBUG_ASSERT(key_length < 0xffff); @@ -3391,9 +3471,10 @@ exit: static void init_check_host(void) { DBUG_ENTER("init_check_host"); - (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip), + (void) my_init_dynamic_array(key_memory_acl_mem, &acl_wild_hosts, + sizeof(struct acl_host_and_ip), acl_users.elements, 1, MYF(0)); - (void) my_hash_init(&acl_check_hosts,system_charset_info, + (void) my_hash_init(key_memory_acl_mem, &acl_check_hosts,system_charset_info, acl_users.elements, 0, 0, (my_hash_get_key) check_get_key, 0, 0); if (!allow_all_hosts) @@ -5040,8 +5121,8 @@ public: bool ok() { return privs != NO_ACL || cols != NO_ACL; } void init_hash() { - my_hash_init2(&hash_columns, 4, system_charset_info, 0, 0, 0, - (my_hash_get_key) get_key_column, 0, 0, 0); + my_hash_init2(key_memory_acl_memex, &hash_columns, 4, system_charset_info, + 0, 0, 0, (my_hash_get_key) get_key_column, 0, 0, 0); } }; @@ -5307,8 +5388,7 @@ column_hash_search(GRANT_TABLE *t, const char *cname, size_t length) { if (!my_hash_inited(&t->hash_columns)) return (GRANT_COLUMN*) 0; - return (GRANT_COLUMN*) my_hash_search(&t->hash_columns, - (uchar*) cname, length); + return (GRANT_COLUMN*)my_hash_search(&t->hash_columns, (uchar*)cname, length); } @@ -5824,19 +5904,19 @@ struct PRIVS_TO_MERGE }; -static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type) +static enum PRIVS_TO_MERGE::what sp_privs_to_merge(enum_sp_type type) { switch (type) { - case TYPE_ENUM_FUNCTION: + case SP_TYPE_FUNCTION: return PRIVS_TO_MERGE::FUNC; - case TYPE_ENUM_PROCEDURE: + case SP_TYPE_PROCEDURE: return PRIVS_TO_MERGE::PROC; - case TYPE_ENUM_PACKAGE: + case SP_TYPE_PACKAGE: return PRIVS_TO_MERGE::PACKAGE_SPEC; - case TYPE_ENUM_PACKAGE_BODY: + case SP_TYPE_PACKAGE_BODY: return PRIVS_TO_MERGE::PACKAGE_BODY; - case TYPE_ENUM_TRIGGER: - case TYPE_ENUM_PROXY: + case SP_TYPE_EVENT: + case SP_TYPE_TRIGGER: break; } DBUG_ASSERT(0); @@ -6229,7 +6309,7 @@ static int update_role_db(int merged, int first, privilege_t access, static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, role_hash_t *rhash) { - Dynamic_array<int> dbs; + Dynamic_array<int> dbs(PSI_INSTRUMENT_MEM); /* Supposedly acl_dbs can be huge, but only a handful of db grants @@ -6448,7 +6528,7 @@ static int update_role_table_columns(GRANT_TABLE *merged, static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee, const char *db, const char *tname, role_hash_t *rhash) { - Dynamic_array<GRANT_TABLE *> grants; + Dynamic_array<GRANT_TABLE *> grants(PSI_INSTRUMENT_MEM); DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither /* @@ -6577,7 +6657,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee, DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither - Dynamic_array<GRANT_NAME *> grants; + Dynamic_array<GRANT_NAME *> grants(PSI_INSTRUMENT_MEM); /* first, collect routine privileges granted to roles in question */ for (uint i=0 ; i < hash->records ; i++) @@ -6638,7 +6718,7 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)), grantee->counter= 1; // Mark the grantee as merged. /* if we'll do db/table/routine privileges, create a hash of role names */ - role_hash_t role_hash(role_key); + role_hash_t role_hash(PSI_INSTRUMENT_MEM, role_key); if (data->what != PRIVS_TO_MERGE::GLOBAL) { role_hash.insert(grantee); @@ -7590,18 +7670,22 @@ static bool grant_load(THD *thd, Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); - (void) my_hash_init(&column_priv_hash, &my_charset_utf8mb3_bin, - 0,0,0, (my_hash_get_key) get_grant_table, - (my_hash_free_key) free_grant_table,0); - (void) my_hash_init(&proc_priv_hash, &my_charset_utf8mb3_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&func_priv_hash, &my_charset_utf8mb3_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8mb3_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&package_body_priv_hash, &my_charset_utf8mb3_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + (void) my_hash_init(key_memory_acl_memex, &column_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, (my_hash_free_key) free_grant_table, 0); + (void) my_hash_init(key_memory_acl_memex, &proc_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &func_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &package_spec_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &package_body_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + init_sql_alloc(key_memory_acl_mem, &grant_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); t_table= tables_priv.table(); c_table= columns_priv.table(); @@ -7682,7 +7766,7 @@ static bool grant_load(THD *thd, continue; } } - stored_procedure_type type= (stored_procedure_type)procs_priv.routine_type()->val_int(); + enum_sp_type type= (enum_sp_type)procs_priv.routine_type()->val_int(); const Sp_handler *sph= Sp_handler::handler(type); if (!sph || !(hash= sph->get_priv_hash())) { @@ -7930,15 +8014,7 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, switch(access->check(orig_want_access, &t_ref->grant.privilege)) { case ACL_INTERNAL_ACCESS_GRANTED: - /* - Currently, - - the information_schema does not subclass ACL_internal_table_access, - there are no per table privilege checks for I_S, - - the performance schema does use per tables checks, but at most - returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'. - so this branch is not used. - */ - DBUG_ASSERT(0); + continue; case ACL_INTERNAL_ACCESS_DENIED: goto err; case ACL_INTERNAL_ACCESS_CHECK_GRANT: @@ -8801,19 +8877,32 @@ static const char *command_array[]= "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD", "SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX", "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", - "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", + "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "BINLOG MONITOR", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", - "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", - "DELETE HISTORY" + "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", "DELETE HISTORY", + "SET USER", "FEDERATED ADMIN", "CONNECTION ADMIN", "READ_ONLY ADMIN", + "REPLICATION SLAVE ADMIN", "REPLICATION MASTER ADMIN", "BINLOG ADMIN" }; static uint command_lengths[]= { - 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, - 14, 13, 11, 5, 7, 17, 14, + 6, 6, 6, 6, 6, 4, 6, + 8, 7, 4, 5, 10, 5, + 5, 14, 5, 23, + 11, 7, 17, 14, + 11, 9, 14, 13, + 11, 5, 7, 17, 14, + 8, 15, 16, 15, + 23, 24, 12 }; +static_assert(array_elements(command_array) == PRIVILEGE_T_MAX_BIT + 1, + "The definition of command_array does not match privilege_t"); +static_assert(array_elements(command_lengths) == PRIVILEGE_T_MAX_BIT + 1, + "The definition of command_lengths does not match privilege_t"); + + static bool print_grants_for_role(THD *thd, ACL_ROLE * role) { char buff[1024]; @@ -12937,7 +13026,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio, static bool ignore_max_password_errors(const ACL_USER *acl_user) { const char *host= acl_user->host.hostname; - return (acl_user->access & SUPER_ACL) + return (acl_user->access & PRIV_IGNORE_MAX_PASSWORD_ERRORS) && (!strcasecmp(host, "localhost") || !strcmp(host, "127.0.0.1") || !strcmp(host, "::1")); @@ -13125,7 +13214,8 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) system_charset_info, user, user_len, thd->charset(), &dummy_errors); - if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME)))) + if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user_buff, + user_len, MYF(MY_WME)))) DBUG_RETURN(1); /* Clear variables that are allocated */ @@ -13384,8 +13474,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, Security_context *sctx= thd->security_ctx; - my_free((char*) sctx->user); - if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME)))) + my_free(const_cast<char*>(sctx->user)); + if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user, user_len, MYF(MY_WME)))) return packet_error; /* The error is set by my_strdup(). */ @@ -13929,6 +14019,8 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) res= do_auth_once(thd, default_auth_plugin_name, &mpvio); } + PSI_CALL_set_connection_type(vio_type(thd->net.vio)); + Security_context * const sctx= thd->security_ctx; const ACL_USER * acl_user= mpvio.acl_user; if (!acl_user) @@ -13966,17 +14058,9 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) */ if (sctx->user) { - if (strcmp(sctx->priv_user, sctx->user)) - { - general_log_print(thd, command, "%s@%s as %s on %s", - sctx->user, sctx->host_or_ip, - sctx->priv_user[0] ? sctx->priv_user : "anonymous", - safe_str(mpvio.db.str)); - } - else - general_log_print(thd, command, (char*) "%s@%s on %s", - sctx->user, sctx->host_or_ip, - safe_str(mpvio.db.str)); + general_log_print(thd, command, (char*) "%s@%s on %s using %s", + sctx->user, sctx->host_or_ip, + safe_str(mpvio.db.str), safe_vio_type_name(thd->net.vio)); } if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS) @@ -14158,7 +14242,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) (longlong) sctx->master_access, mpvio.db.str)); if (command == COM_CONNECT && - !(thd->main_security_ctx.master_access & SUPER_ACL)) + !(thd->main_security_ctx.master_access & PRIV_IGNORE_MAX_CONNECTIONS)) { if (*thd->scheduler->connection_count > *thd->scheduler->max_connections) { // too many connections @@ -14220,16 +14304,17 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) thd->net.net_skip_rest_factor= 2; // skip at most 2*max_packet_size if (mpvio.auth_info.external_user[0]) - sctx->external_user= my_strdup(mpvio.auth_info.external_user, MYF(0)); + sctx->external_user= my_strdup(key_memory_MPVIO_EXT_auth_info, + mpvio.auth_info.external_user, MYF(0)); if (res == CR_OK_HANDSHAKE_COMPLETE) thd->get_stmt_da()->disable_status(); else my_ok(thd); - PSI_CALL_set_thread_user_host - (thd->main_security_ctx.user, (uint)strlen(thd->main_security_ctx.user), - thd->main_security_ctx.host_or_ip, (uint)strlen(thd->main_security_ctx.host_or_ip)); + PSI_CALL_set_thread_account + (thd->main_security_ctx.user, static_cast<uint>(strlen(thd->main_security_ctx.user)), + thd->main_security_ctx.host_or_ip, static_cast<uint>(strlen(thd->main_security_ctx.host_or_ip))); /* Ready to handle queries */ DBUG_RETURN(0); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 000228945f4..2cf1637c8db 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -167,8 +167,6 @@ enum ACL_internal_access_result /** Access granted for all the requested privileges, do not use the grant tables. - This flag is used only for the INFORMATION_SCHEMA privileges, - for compatibility reasons. */ ACL_INTERNAL_ACCESS_GRANTED, /** Access denied, do not use the grant tables. */ diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index e5347f2fda4..cfc48c82b4d 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -26,7 +26,6 @@ #include "sql_view.h" // view_checksum #include "sql_table.h" // mysql_recreate_table #include "debug_sync.h" // DEBUG_SYNC -#include "sql_acl.h" // *_ACL #include "sp.h" // Sroutine_hash_entry #include "sql_parse.h" // check_table_access #include "strfunc.h" @@ -122,9 +121,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, Let us try to open at least a .FRM for this table. */ - table_list->mdl_request.init(MDL_key::TABLE, - table_list->db.str, table_list->table_name.str, - MDL_EXCLUSIVE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE, + table_list->db.str, table_list->table_name.str, + MDL_EXCLUSIVE, MDL_TRANSACTION); if (lock_table_names(thd, table_list, table_list->next_global, thd->variables.lock_wait_timeout, 0)) @@ -547,8 +546,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, close_thread_tables(thd); table->table= NULL; thd->mdl_context.release_transactional_locks(); - table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str, - MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str, + table->table_name.str, MDL_SHARED_NO_READ_WRITE, + MDL_TRANSACTION); } #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -822,8 +822,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, close_thread_tables(thd); table->table= NULL; thd->mdl_context.release_transactional_locks(); - table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str, - MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str, + table->table_name.str, MDL_SHARED_NO_READ_WRITE, + MDL_TRANSACTION); table->mdl_request.set_type(MDL_SHARED_READ); table->lock_type= TL_READ; diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 0828e1b7ba8..23e2e3e097f 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -25,6 +25,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) :drop_list(rhs.drop_list, mem_root), alter_list(rhs.alter_list, mem_root), key_list(rhs.key_list, mem_root), + alter_rename_key_list(rhs.alter_rename_key_list, mem_root), create_list(rhs.create_list, mem_root), check_constraint_list(rhs.check_constraint_list, mem_root), flags(rhs.flags), partition_flags(rhs.partition_flags), @@ -46,6 +47,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) list_copy_and_replace_each_value(drop_list, mem_root); list_copy_and_replace_each_value(alter_list, mem_root); list_copy_and_replace_each_value(key_list, mem_root); + list_copy_and_replace_each_value(alter_rename_key_list, mem_root); list_copy_and_replace_each_value(create_list, mem_root); /* partition_names are not deeply copied currently */ } diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 41408a91836..a553c31346a 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -19,6 +19,7 @@ class Alter_drop; class Alter_column; +class Alter_rename_key; class Key; /** @@ -87,6 +88,8 @@ public: List<Alter_column> alter_list; // List of keys, used by both CREATE and ALTER TABLE. List<Key> key_list; + // List of keys to be renamed. + List<Alter_rename_key> alter_rename_key_list; // List of columns, used by both CREATE and ALTER TABLE. List<Create_field> create_list; @@ -123,6 +126,7 @@ public: drop_list.empty(); alter_list.empty(); key_list.empty(); + alter_rename_key_list.empty(); create_list.empty(); check_constraint_list.empty(); flags= 0; diff --git a/sql/sql_analyze_stmt.cc b/sql/sql_analyze_stmt.cc index fdabcf1e494..2f87b9b0d40 100644 --- a/sql/sql_analyze_stmt.cc +++ b/sql/sql_analyze_stmt.cc @@ -26,6 +26,7 @@ void Filesort_tracker::print_json_members(Json_writer *writer) { const char *varied_str= "(varied across executions)"; + String str; if (!get_r_loops()) writer->add_member("r_loops").add_null(); @@ -78,6 +79,28 @@ void Filesort_tracker::print_json_members(Json_writer *writer) else writer->add_size(sort_buffer_size); } + + get_data_format(&str); + writer->add_member("r_sort_mode").add_str(str.c_ptr(), str.length()); +} + +void Filesort_tracker::get_data_format(String *str) +{ + if (r_sort_keys_packed) + str->append("packed_sort_key"); + else + str->append("sort_key"); + str->append(","); + + if (r_using_addons) + { + if (r_packed_addon_fields) + str->append("packed_addon_fields"); + else + str->append("addon_fields"); + } + else + str->append("rowid"); } void attach_gap_time_tracker(THD *thd, Gap_time_tracker *gap_tracker, diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h index 9d5151c3be2..bc7c60a318b 100644 --- a/sql/sql_analyze_stmt.h +++ b/sql/sql_analyze_stmt.h @@ -221,7 +221,10 @@ public: time_tracker(do_timing), r_limit(0), r_used_pq(0), r_examined_rows(0), r_sorted_rows(0), r_output_rows(0), sort_passes(0), - sort_buffer_size(0) + sort_buffer_size(0), + r_using_addons(false), + r_packed_addon_fields(false), + r_sort_keys_packed(false) {} /* Functions that filesort uses to report various things about its execution */ @@ -263,6 +266,18 @@ public: else sort_buffer_size= bufsize; } + + inline void report_addon_fields_format(bool addons_packed) + { + r_using_addons= true; + r_packed_addon_fields= addons_packed; + } + inline void report_sort_keys_format(bool sort_keys_packed) + { + r_sort_keys_packed= sort_keys_packed; + } + + void get_data_format(String *str); /* Functions to get the statistics */ void print_json_members(Json_writer *writer); @@ -322,6 +337,9 @@ private: other - value */ ulonglong sort_buffer_size; + bool r_using_addons; + bool r_packed_addon_fields; + bool r_sort_keys_packed; }; diff --git a/sql/sql_array.h b/sql/sql_array.h index 44dde114d62..b6de1b18d78 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -114,21 +114,21 @@ template <class Elem> class Dynamic_array { DYNAMIC_ARRAY array; public: - Dynamic_array(uint prealloc=16, uint increment=16) + Dynamic_array(PSI_memory_key psi_key, uint prealloc=16, uint increment=16) { - init(prealloc, increment); + init(psi_key, prealloc, increment); } Dynamic_array(MEM_ROOT *root, uint prealloc=16, uint increment=16) { void *init_buffer= alloc_root(root, sizeof(Elem) * prealloc); - my_init_dynamic_array2(&array, sizeof(Elem), init_buffer, + init_dynamic_array2(root->m_psi_key, &array, sizeof(Elem), init_buffer, prealloc, increment, MYF(0)); } - void init(uint prealloc=16, uint increment=16) + void init(PSI_memory_key psi_key, uint prealloc=16, uint increment=16) { - init_dynamic_array2(&array, sizeof(Elem), 0, prealloc, increment, MYF(0)); + init_dynamic_array2(psi_key, &array, sizeof(Elem), 0, prealloc, increment, MYF(0)); } /** @@ -170,6 +170,11 @@ public: return ((const Elem*)array.buffer) + array.elements - 1; } + const Elem *end() const + { + return back() + 1; + } + /// @returns pointer to n-th element Elem *get_pos(size_t idx) { @@ -182,7 +187,6 @@ public: return ((const Elem*)array.buffer) + idx; } - /** @retval false ok @retval true OOM, @c my_error() has been called. @@ -240,10 +244,16 @@ public: freeze_size(&array); } + bool reserve(size_t new_size) + { + return allocate_dynamic(&array, (uint)new_size); + } + + bool resize(size_t new_size, Elem default_val) { size_t old_size= elements(); - if (unlikely(allocate_dynamic(&array, (uint)new_size))) + if (reserve(new_size)) return true; if (new_size > old_size) diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index ed175ae4865..3e9379ebe33 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -88,7 +88,7 @@ static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg) if (unlikely(!thd->audit_class_plugins.buffer)) { /* specify some reasonable initialization defaults */ - my_init_dynamic_array(&thd->audit_class_plugins, + my_init_dynamic_array(PSI_INSTRUMENT_ME, &thd->audit_class_plugins, sizeof(plugin_ref), 16, 16, MYF(0)); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c88aef09c96..c41e08e4b8c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -30,9 +30,6 @@ #include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL #include "sql_parse.h" // check_table_access #include "sql_insert.h" // kill_delayed_threads -#include "sql_acl.h" // *_ACL, check_grant_all_columns, - // check_column_grant_in_table_ref, - // get_column_grant #include "sql_partition.h" // ALTER_PARTITION_PARAM_TYPE #include "sql_derived.h" // mysql_derived_prepare, // mysql_handle_derived, @@ -437,7 +434,8 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, MDL_request *mdl_request= new (thd->mem_root) MDL_request; if (mdl_request == NULL) DBUG_RETURN(true); - mdl_request->init(&table->mdl_request.key, MDL_EXCLUSIVE, MDL_STATEMENT); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &table->mdl_request.key, + MDL_EXCLUSIVE, MDL_STATEMENT); mdl_requests.push_front(mdl_request); } @@ -566,12 +564,12 @@ bool flush_tables(THD *thd, flush_tables_type flag) write after last time all tables was closed. */ - if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table), + if (!(tmp_table= (TABLE*) my_malloc(PSI_INSTRUMENT_ME, sizeof(*tmp_table), MYF(MY_WME | MY_THREAD_SPECIFIC)))) DBUG_RETURN(1); - my_init_dynamic_array(&collect_arg.shares, sizeof(TABLE_SHARE*), 100, 100, - MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares, + sizeof(TABLE_SHARE*), 100, 100, MYF(0)); collect_arg.flush_type= flag; if (tdc_iterate(thd, (my_hash_walk_action) tc_collect_used_shares, &collect_arg, true)) @@ -1577,10 +1575,9 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx, DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) || !(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)); - mdl_request_shared.init(&mdl_request->key, - (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ? - MDL_SHARED : MDL_SHARED_HIGH_PRIO, - MDL_TRANSACTION); + MDL_REQUEST_INIT_BY_KEY(&mdl_request_shared, &mdl_request->key, + flags & MYSQL_OPEN_FORCE_SHARED_MDL ? MDL_SHARED : MDL_SHARED_HIGH_PRIO, + MDL_TRANSACTION); mdl_request= &mdl_request_shared; } @@ -2064,7 +2061,8 @@ retry_share: { enum open_frm_error error; /* make a new table */ - if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME)))) + if (!(table=(TABLE*) my_malloc(key_memory_TABLE, sizeof(*table), + MYF(MY_WME)))) goto err_lock; error= open_table_from_share(thd, share, &table_list->alias, @@ -2150,8 +2148,8 @@ retry_share: DBUG_RETURN(TRUE); } - protection_request.init(MDL_key::BACKUP, "", "", mdl_type, - MDL_STATEMENT); + MDL_REQUEST_INIT(&protection_request, MDL_key::BACKUP, "", "", mdl_type, + MDL_STATEMENT); /* Install error handler which if possible will convert deadlock error @@ -3004,7 +3002,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) thd->clear_error(); - if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME)))) + if (!(entry= (TABLE*)my_malloc(key_memory_TABLE, sizeof(TABLE), MYF(MY_WME)))) return result; if (!(share= tdc_acquire_share(thd, table_list, GTS_TABLE))) @@ -4043,9 +4041,8 @@ lock_table_names(THD *thd, const DDL_options_st &options, MDL_request *schema_request= new (thd->mem_root) MDL_request; if (schema_request == NULL) DBUG_RETURN(TRUE); - schema_request->init(MDL_key::SCHEMA, table->db.str, "", - MDL_INTENTION_EXCLUSIVE, - MDL_TRANSACTION); + MDL_REQUEST_INIT(schema_request, MDL_key::SCHEMA, table->db.str, "", + MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION); mdl_requests.push_front(schema_request); } @@ -4067,7 +4064,8 @@ lock_table_names(THD *thd, const DDL_options_st &options, if (thd->has_read_only_protection()) DBUG_RETURN(true); - global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT); + MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, + MDL_STATEMENT); mdl_savepoint= thd->mdl_context.mdl_savepoint(); while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) && @@ -5767,7 +5765,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, replace. If the item was aliased by the user, set the alias to the replacing item. */ - if (*ref && !(*ref)->is_autogenerated_name) + if (*ref && !(*ref)->is_autogenerated_name()) item->set_name(thd, (*ref)->name); if (register_tree_change) thd->change_item_tree(ref, item); @@ -5858,7 +5856,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si replace. If the item was aliased by the user, set the alias to the replacing item. */ - if (*ref && !(*ref)->is_autogenerated_name) + if (*ref && !(*ref)->is_autogenerated_name()) item->set_name(thd, (*ref)->name); if (register_tree_change && arena) thd->restore_active_arena(arena, &backup); diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 44a885bf0eb..ea91f68f360 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -144,7 +144,7 @@ int binlog_defragment(THD *thd) } thd->lex->comment.str= // to be freed by the caller - (char *) my_malloc(thd->lex->comment.length, MYF(MY_WME)); + (char *) my_malloc(PSI_INSTRUMENT_ME, thd->lex->comment.length, MYF(MY_WME)); if (!thd->lex->comment.str) { my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); @@ -189,7 +189,7 @@ void mysql_client_binlog_statement(THD* thd) thd->lex->comment.length : 2048), thd->lex->comment.str)); - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_BINLOG)) DBUG_VOID_RETURN; /* @@ -242,7 +242,8 @@ void mysql_client_binlog_statement(THD* thd) } decoded_len= my_base64_needed_decoded_length((int)coded_len); - if (!(buf= (char *) my_malloc(decoded_len, MYF(MY_WME)))) + if (!(buf= (char *) my_malloc(key_memory_binlog_statement_buffer, + decoded_len, MYF(MY_WME)))) { my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); goto end; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 5b649b739c6..00681ba8e2a 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2727,8 +2727,8 @@ size_t Query_cache::init_cache() DUMP(this); - (void) my_hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0, - query_cache_query_get_key, 0, 0); + (void) my_hash_init(key_memory_Query_cache, &queries, &my_charset_bin, + def_query_hash_size, 0,0, query_cache_query_get_key,0,0); #ifndef FN_NO_CASE_SENSE /* If lower_case_table_names!=0 then db and table names are already @@ -2738,8 +2738,8 @@ size_t Query_cache::init_cache() lower_case_table_names == 0 then we should distinguish my_table and MY_TABLE cases and so again can use binary collation. */ - (void) my_hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0, - query_cache_table_get_key, 0, 0); + (void) my_hash_init(key_memory_Query_cache, &tables, &my_charset_bin, + def_table_hash_size, 0,0, query_cache_table_get_key, 0,0); #else /* On windows, OS/2, MacOS X with HFS+ or any other case insensitive @@ -2749,11 +2749,9 @@ size_t Query_cache::init_cache() file system) and so should use case insensitive collation for comparison. */ - (void) my_hash_init(&tables, - lower_case_table_names ? &my_charset_bin : - files_charset_info, - def_table_hash_size, 0, 0,query_cache_table_get_key, - 0, 0); + (void) my_hash_init(PSI_INSTRUMENT_ME, &tables, lower_case_table_names ? + &my_charset_bin : files_charset_info, + def_table_hash_size, 0,0, query_cache_table_get_key, 0,0); #endif queries_in_cache = 0; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2ffb61a98f2..2143a9d4008 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -632,8 +632,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), - protocol_text(this), protocol_binary(this), - m_current_stage_key(0), + protocol_text(this), protocol_binary(this), initial_status_var(0), + m_current_stage_key(0), m_psi(0), in_sub_stmt(0), log_all_errors(0), binlog_unsafe_warning_flags(0), binlog_table_maps(0), @@ -643,6 +643,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) accessed_rows_and_keys(0), m_digest(NULL), m_statement_psi(NULL), + m_transaction_psi(NULL), m_idle_psi(NULL), col_access(NO_ACL), thread_id(id), @@ -743,8 +744,9 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) the destructor works OK in case of an error. The main_mem_root will be re-initialized in init_for_queries(). */ - init_sql_alloc(&main_mem_root, "THD::main_mem_root", - ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_thd_main_mem_root, + &main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0, + MYF(MY_THREAD_SPECIFIC)); /* Allocation of user variables for binary logging is always done with main @@ -756,7 +758,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) thread_stack= 0; scheduler= thread_scheduler; // Will be fixed later event_scheduler.data= 0; - event_scheduler.m_psi= 0; skip_wait_timeout= false; catalog= (char*)"std"; // the only catalog we have for now main_security_ctx.init(); @@ -843,12 +844,13 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) profiling.set_thd(this); #endif user_connect=(USER_CONN *)0; - my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, - (my_hash_get_key) get_var_key, + my_hash_init(key_memory_user_var_entry, &user_vars, system_charset_info, + USER_VARS_HASH_SIZE, 0, 0, (my_hash_get_key) get_var_key, (my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC); - my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0, - (my_hash_get_key) get_sequence_last_key, - (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC); + my_hash_init(PSI_INSTRUMENT_ME, &sequences, system_charset_info, + SEQUENCES_HASH_SIZE, 0, 0, (my_hash_get_key) + get_sequence_last_key, (my_hash_free_key) free_sequence_last, + HASH_THREAD_SPECIFIC); sp_proc_cache= NULL; sp_func_cache= NULL; @@ -857,7 +859,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) /* For user vars replication*/ if (opt_bin_log) - my_init_dynamic_array(&user_var_events, + my_init_dynamic_array(key_memory_user_var_entry, &user_var_events, sizeof(BINLOG_USER_VAR_EVENT *), 16, 16, MYF(0)); else bzero((char*) &user_var_events, sizeof(user_var_events)); @@ -885,7 +887,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) m_token_array= NULL; if (max_digest_length > 0) { - m_token_array= (unsigned char*) my_malloc(max_digest_length, + m_token_array= (unsigned char*) my_malloc(PSI_INSTRUMENT_ME, + max_digest_length, MYF(MY_WME|MY_THREAD_SPECIFIC)); } @@ -1185,19 +1188,9 @@ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size) extern "C" void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid) { -#ifdef WITH_WSREP - if (!thd->wsrep_xid.is_null()) - { - *xid = *(MYSQL_XID *) &thd->wsrep_xid; - return; - } -#endif /* WITH_WSREP */ - *xid= thd->transaction.xid_state.is_explicit_XA() ? - *(MYSQL_XID *) thd->transaction.xid_state.get_xid() : - *(MYSQL_XID *) &thd->transaction.implicit_xid; + *xid = *(MYSQL_XID *) thd->get_xid(); } - extern "C" my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode) @@ -1448,12 +1441,13 @@ void THD::change_user(void) init(); stmt_map.reset(); - my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, - (my_hash_get_key) get_var_key, - (my_hash_free_key) free_user_var, 0); - my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0, - (my_hash_get_key) get_sequence_last_key, - (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC); + my_hash_init(key_memory_user_var_entry, &user_vars, system_charset_info, + USER_VARS_HASH_SIZE, 0, 0, (my_hash_get_key) get_var_key, + (my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC); + my_hash_init(key_memory_user_var_entry, &sequences, system_charset_info, + SEQUENCES_HASH_SIZE, 0, 0, (my_hash_get_key) + get_sequence_last_key, (my_hash_free_key) free_sequence_last, + HASH_THREAD_SPECIFIC); sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_func_cache); sp_cache_clear(&sp_package_spec_cache); @@ -1490,7 +1484,8 @@ bool THD::set_db(const LEX_CSTRING *new_db) const char *tmp= NULL; if (new_db->str) { - if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATAL)))) + if (!(tmp= my_strndup(key_memory_THD_db, new_db->str, new_db->length, + MYF(MY_WME | ME_FATAL)))) result= 1; } @@ -1682,6 +1677,8 @@ THD::~THD() DBUG_ENTER("~THD()"); /* Make sure threads are not available via server_threads. */ assert_not_linked(); + if (m_psi) + PSI_CALL_set_thread_THD(m_psi, 0); /* In error cases, thd may not be current thd. We have to fix this so @@ -3929,12 +3926,12 @@ Statement_map::Statement_map() : START_STMT_HASH_SIZE = 16, START_NAME_HASH_SIZE = 16 }; - my_hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0, - get_statement_id_as_hash_key, + my_hash_init(key_memory_prepared_statement_map, &st_hash, &my_charset_bin, + START_STMT_HASH_SIZE, 0, 0, get_statement_id_as_hash_key, delete_statement_as_hash_key, MYF(0)); - my_hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0, + my_hash_init(key_memory_prepared_statement_map, &names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0, (my_hash_get_key) get_stmt_name_hash_key, - NULL,MYF(0)); + NULL, MYF(0)); } @@ -4338,8 +4335,8 @@ void Security_context::skip_grants() bool Security_context::set_user(char *user_arg) { - my_free((char*) user); - user= my_strdup(user_arg, MYF(0)); + my_free(const_cast<char*>(user)); + user= my_strdup(key_memory_MPVIO_EXT_auth_info, user_arg, MYF(0)); return user == 0; } @@ -4827,6 +4824,7 @@ MYSQL_THD create_background_thd() auto thd_mysysvar= pthread_getspecific(THR_KEY_mysys); auto thd= new THD(0); pthread_setspecific(THR_KEY_mysys, save_mysysvar); + thd->set_psi(PSI_CALL_get_thread()); /* Workaround the adverse effect of incrementing thread_count @@ -6601,7 +6599,8 @@ CPP_UNNAMED_NS_START } else { - m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME)); + m_memory= (uchar *) my_malloc(key_memory_Row_data_memory_memory, + total_length, MYF(MY_WME)); m_release_memory_on_destruction= TRUE; } } @@ -7785,3 +7784,8 @@ bool THD::timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts, } return 0; } + +THD_list_iterator *THD_list_iterator::iterator() +{ + return &server_threads; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 13b2659789d..acd304e24ea 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -106,7 +106,8 @@ enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, SLAVE_EXEC_MODE_LAST_BIT }; enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO, SLAVE_RUN_TRIGGERS_FOR_RBR_YES, - SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING}; + SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING, + SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE}; enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY, SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY}; @@ -333,17 +334,40 @@ public: class Alter_column :public Sql_alloc { public: - const char *name; + LEX_CSTRING name; + LEX_CSTRING new_name; Virtual_column_info *default_value; bool alter_if_exists; - Alter_column(const char *par_name, Virtual_column_info *expr, bool par_exists) - :name(par_name), default_value(expr), alter_if_exists(par_exists) {} + Alter_column(LEX_CSTRING par_name, Virtual_column_info *expr, bool par_exists) + :name(par_name), new_name{NULL, 0}, default_value(expr), alter_if_exists(par_exists) {} + Alter_column(LEX_CSTRING par_name, LEX_CSTRING _new_name) + :name(par_name), new_name(_new_name), default_value(NULL), alter_if_exists(false) {} /** Used to make a clone of this object for ALTER/CREATE TABLE @sa comment for Key_part_spec::clone */ Alter_column *clone(MEM_ROOT *mem_root) const { return new (mem_root) Alter_column(*this); } + bool is_rename() + { + DBUG_ASSERT(!new_name.str || !default_value); + return new_name.str; + } +}; + + +class Alter_rename_key : public Sql_alloc +{ +public: + LEX_CSTRING old_name; + LEX_CSTRING new_name; + + Alter_rename_key(LEX_CSTRING old_name_arg, LEX_CSTRING new_name_arg) + : old_name(old_name_arg), new_name(new_name_arg) {} + + Alter_rename_key *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Alter_rename_key(*this); } + }; @@ -936,6 +960,10 @@ typedef struct system_status_var #define last_system_status_var questions #define last_cleared_system_status_var local_memory_used +/* Number of contiguous global status variables. */ +const int COUNT_GLOBAL_STATUS_VARS= (offsetof(STATUS_VAR, last_system_status_var) / + sizeof(ulong)) + 1; + /* Global status variables */ @@ -993,6 +1021,39 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs) return MY_TEST(cs->mbminlen == 1); } +/** THD registry */ +class THD_list_iterator +{ +protected: + I_List<THD> threads; + mutable mysql_rwlock_t lock; + +public: + + /** + Iterates registered threads. + + @param action called for every element + @param argument opque argument passed to action + + @return + @retval 0 iteration completed successfully + @retval 1 iteration was interrupted (action returned 1) + */ + template <typename T> int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0) + { + int res= 0; + mysql_rwlock_rdlock(&lock); + I_List_iterator<THD> it(threads); + while (auto tmp= it++) + if ((res= action(tmp, arg))) + break; + mysql_rwlock_unlock(&lock); + return res; + } + static THD_list_iterator *iterator(); +}; + #ifdef MYSQL_SERVER void free_tmp_table(THD *thd, TABLE *entry); @@ -1905,9 +1966,8 @@ public: m_reopen_array(NULL), m_locked_tables_count(0) { - init_sql_alloc(&m_locked_tables_root, "Locked_tables_list", - MEM_ROOT_BLOCK_SIZE, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_locked_table_list, &m_locked_tables_root, + MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); } void unlock_locked_tables(THD *thd); void unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket); @@ -2348,9 +2408,22 @@ public: */ const char *proc_info; + void set_psi(PSI_thread *psi) + { + my_atomic_storeptr((void*volatile*)&m_psi, psi); + } + + PSI_thread* get_psi() + { + return static_cast<PSI_thread*>(my_atomic_loadptr((void*volatile*)&m_psi)); + } + private: unsigned int m_current_stage_key; + /** Performance schema thread instrumentation for this session. */ + PSI_thread *m_psi; + public: void enter_stage(const PSI_stage_info *stage, const char *calling_func, @@ -2367,7 +2440,7 @@ public: calling_line); #endif #ifdef HAVE_PSI_THREAD_INTERFACE - MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line); + m_stage_progress_psi= MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line); #endif } @@ -2666,9 +2739,8 @@ public: { bzero((char*)this, sizeof(*this)); implicit_xid.null(); - init_sql_alloc(&mem_root, "THD::transactions", - ALLOC_ROOT_MIN_BLOCK_SIZE, 0, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_thd_transactions, &mem_root, + ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); } } transaction; Global_read_lock global_read_lock; @@ -2966,6 +3038,8 @@ public: PROFILING profiling; #endif + /** Current stage progress instrumentation. */ + PSI_stage_progress *m_stage_progress_psi; /** Current statement digest. */ sql_digest_state *m_digest; /** Current statement digest token array. */ @@ -2979,6 +3053,14 @@ public: /** Current statement instrumentation state. */ PSI_statement_locker_state m_statement_state; #endif /* HAVE_PSI_STATEMENT_INTERFACE */ + + /** Current transaction instrumentation. */ + PSI_transaction_locker *m_transaction_psi; +#ifdef HAVE_PSI_TRANSACTION_INTERFACE + /** Current transaction instrumentation state. */ + PSI_transaction_locker_state m_transaction_state; +#endif /* HAVE_PSI_TRANSACTION_INTERFACE */ + /** Idle instrumentation. */ PSI_idle_locker *m_idle_psi; #ifdef HAVE_PSI_IDLE_INTERFACE @@ -4745,6 +4827,17 @@ public: LF_PINS *xid_hash_pins; bool fix_xid_hash_pins(); + const XID *get_xid() const + { +#ifdef WITH_WSREP + if (!wsrep_xid.is_null()) + return &wsrep_xid; +#endif /* WITH_WSREP */ + return transaction.xid_state.is_explicit_XA() ? + transaction.xid_state.get_xid() : + &transaction.implicit_xid; + } + /* Members related to temporary tables. */ public: /* Opened table states. */ @@ -6253,8 +6346,52 @@ public: /* Structs used when sorting */ struct SORT_FIELD_ATTR { - uint length; /* Length of sort field */ - uint suffix_length; /* Length suffix (0-4) */ + /* + If using mem-comparable fixed-size keys: + length of the mem-comparable image of the field, in bytes. + + If using packed keys: still the same? Not clear what is the use of it. + */ + uint length; + + /* + For most datatypes, this is 0. + The exception are the VARBINARY columns. + For those columns, the comparison actually compares + + (value_prefix(N), suffix=length(value)) + + Here value_prefix is either the whole value or its prefix if it was too + long, and the suffix is the length of the original value. + (this way, for values X and Y: if X=prefix(Y) then X compares as less + than Y + */ + uint suffix_length; + + /* + If using packed keys, number of bytes that are used to store the length + of the packed key. + + */ + uint length_bytes; + + /* Max. length of the original value, in bytes */ + uint original_length; + enum Type { FIXED_SIZE, VARIABLE_SIZE } type; + /* + TRUE : if the item or field is NULLABLE + FALSE : otherwise + */ + bool maybe_null; + CHARSET_INFO *cs; + uint pack_sort_string(uchar *to, const LEX_CSTRING &str, + CHARSET_INFO *cs) const; + int compare_packed_fixed_size_vals(uchar *a, size_t *a_len, + uchar *b, size_t *b_len); + int compare_packed_varstrings(uchar *a, size_t *a_len, + uchar *b, size_t *b_len); + bool check_if_packing_possible(THD *thd) const; + bool is_variable_sized() { return type == VARIABLE_SIZE; } }; @@ -6795,8 +6932,8 @@ inline int handler::ha_write_tmp_row(uchar *buf) int error; MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_write_count); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, - { error= write_row(buf); }) + TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, + { error= write_row(buf); }) MYSQL_INSERT_ROW_DONE(error); return error; } @@ -6806,7 +6943,7 @@ inline int handler::ha_delete_tmp_row(uchar *buf) int error; MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_delete_count); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, MAX_KEY, 0, + TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error, { error= delete_row(buf); }) MYSQL_DELETE_ROW_DONE(error); return error; @@ -6817,13 +6954,12 @@ inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data) int error; MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_update_count); - TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, - { error= update_row(old_data, new_data);}) + TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, error, + { error= update_row(old_data, new_data);}) MYSQL_UPDATE_ROW_DONE(error); return error; } - extern pthread_attr_t *get_connection_attrib(void); /** @@ -7191,11 +7327,8 @@ private: /** THD registry */ -class THD_list +class THD_list: public THD_list_iterator { - I_List<THD> threads; - mutable mysql_rwlock_t lock; - public: /** Constructor replacement. @@ -7243,28 +7376,6 @@ public: thd->unlink(); mysql_rwlock_unlock(&lock); } - - /** - Iterates registered threads. - - @param action called for every element - @param argument opque argument passed to action - - @return - @retval 0 iteration completed successfully - @retval 1 iteration was interrupted (action returned 1) - */ - template <typename T> int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0) - { - int res= 0; - mysql_rwlock_rdlock(&lock); - I_List_iterator<THD> it(threads); - while (auto tmp= it++) - if ((res= action(tmp, arg))) - break; - mysql_rwlock_unlock(&lock); - return res; - } }; extern THD_list server_threads; diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 1f8f2dcabc9..ce34852117f 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -38,7 +38,7 @@ enum enum_sql_command { SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_STATUS, SQLCOM_SHOW_ENGINE_LOGS, SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_MUTEX, - SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, + SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_BINLOG_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, SQLCOM_SHOW_TRIGGERS, diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index e2a3c482ae4..d5a90089da4 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -35,7 +35,6 @@ #include "sql_db.h" // mysql_change_db #include "hostname.h" // inc_host_errors, ip_to_hostname, // reset_host_errors -#include "privilege.h" // acl_getroot, SUPER_ACL #include "sql_callback.h" #ifdef WITH_WSREP @@ -81,8 +80,8 @@ int get_or_create_user_conn(THD *thd, const char *user, { /* First connection for user; Create a user connection object */ if (!(uc= ((struct user_conn*) - my_malloc(sizeof(struct user_conn) + temp_len+1, - MYF(MY_WME))))) + my_malloc(key_memory_user_conn, + sizeof(struct user_conn) + temp_len+1, MYF(MY_WME))))) { /* MY_WME ensures an error is set in THD. */ return_val= 1; @@ -140,7 +139,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) if (global_system_variables.max_user_connections && !uc->user_resources.user_conn && global_system_variables.max_user_connections < uc->connections && - !(thd->security_ctx->master_access & SUPER_ACL)) + !(thd->security_ctx->master_access & PRIV_IGNORE_MAX_USER_CONNECTIONS)) { my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); error=1; @@ -322,9 +321,9 @@ extern "C" void free_user(struct user_conn *uc) void init_max_user_conn(void) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - my_hash_init(&hash_user_connections, system_charset_info, max_connections, - 0, 0, (my_hash_get_key) get_key_conn, - (my_hash_free_key) free_user, 0); + my_hash_init(key_memory_user_conn, &hash_user_connections, + system_charset_info, max_connections, 0, 0, (my_hash_get_key) + get_key_conn, (my_hash_free_key) free_user, 0); #endif } @@ -483,14 +482,14 @@ void init_user_stats(USER_STATS *user_stats, void init_global_user_stats(void) { - my_hash_init(&global_user_stats, system_charset_info, max_connections, + my_hash_init(PSI_INSTRUMENT_ME, &global_user_stats, system_charset_info, max_connections, 0, 0, (my_hash_get_key) get_key_user_stats, (my_hash_free_key) free_user_stats, 0); } void init_global_client_stats(void) { - my_hash_init(&global_client_stats, system_charset_info, max_connections, + my_hash_init(PSI_INSTRUMENT_ME, &global_client_stats, system_charset_info, max_connections, 0, 0, (my_hash_get_key) get_key_user_stats, (my_hash_free_key) free_user_stats, 0); } @@ -509,8 +508,8 @@ extern "C" void free_table_stats(TABLE_STATS* table_stats) void init_global_table_stats(void) { - my_hash_init(&global_table_stats, system_charset_info, max_connections, - 0, 0, (my_hash_get_key) get_key_table_stats, + my_hash_init(PSI_INSTRUMENT_ME, &global_table_stats, system_charset_info, + max_connections, 0, 0, (my_hash_get_key) get_key_table_stats, (my_hash_free_key) free_table_stats, 0); } @@ -528,8 +527,8 @@ extern "C" void free_index_stats(INDEX_STATS* index_stats) void init_global_index_stats(void) { - my_hash_init(&global_index_stats, system_charset_info, max_connections, - 0, 0, (my_hash_get_key) get_key_index_stats, + my_hash_init(PSI_INSTRUMENT_ME, &global_index_stats, system_charset_info, + max_connections, 0, 0, (my_hash_get_key) get_key_index_stats, (my_hash_free_key) free_index_stats, 0); } @@ -571,7 +570,7 @@ static bool increment_count_by_name(const char *name, size_t name_length, { /* First connection for this user or client */ if (!(user_stats= ((USER_STATS*) - my_malloc(sizeof(USER_STATS), + my_malloc(PSI_INSTRUMENT_ME, sizeof(USER_STATS), MYF(MY_WME | MY_ZEROFILL))))) return TRUE; // Out of memory @@ -880,7 +879,7 @@ int thd_set_peer_addr(THD *thd, } my_free((void *)thd->main_security_ctx.ip); - if (!(thd->main_security_ctx.ip = my_strdup(ip, MYF(MY_WME)))) + if (!(thd->main_security_ctx.ip = my_strdup(PSI_INSTRUMENT_ME, ip, MYF(MY_WME)))) { /* No error accounting per IP in host_cache, @@ -1246,7 +1245,8 @@ void prepare_new_connection_state(THD* thd) thd->set_command(COM_SLEEP); thd->init_for_queries(); - if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL)) + if (opt_init_connect.length && + !(sctx->master_access & PRIV_IGNORE_INIT_CONNECT)) { execute_init_command(thd, &opt_init_connect, &LOCK_sys_init_connect); if (unlikely(thd->is_error())) @@ -1435,6 +1435,10 @@ end_thread: !(connect= cache_thread(thd))) break; + /* Create new instrumentation for the new THD job */ + PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, thd, + thd->thread_id)); + if (!(connect->create_thd(thd))) { /* Out of resources. Free thread to get more resources */ @@ -1449,13 +1453,6 @@ end_thread: */ thd->store_globals(); - /* - Create new instrumentation for the new THD job, - and attach it to this running pthread. - */ - PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, - thd, thd->thread_id)); - /* reset abort flag for the thread */ thd->mysys_var->abort= 0; thd->thr_create_utime= microsecond_interval_timer(); @@ -1576,5 +1573,14 @@ THD *CONNECT::create_thd(THD *thd) thd->scheduler= scheduler; thd->real_id= pthread_self(); /* Duplicates THD::store_globals() setting. */ + + /* Attach PSI instrumentation to the new THD */ + + PSI_thread *psi= PSI_CALL_get_thread(); + PSI_CALL_set_thread_os_id(psi); + PSI_CALL_set_thread_THD(psi, thd); + PSI_CALL_set_thread_id(psi, thd->thread_id); + thd->set_psi(psi); + DBUG_RETURN(thd); } diff --git a/sql/sql_const.h b/sql/sql_const.h index f7c820c727b..a3f0e35ac47 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -309,4 +309,6 @@ #define QUERY_PRIOR 6 #endif /* __WIN92__ */ +#define SP_PSI_STATEMENT_INFO_COUNT 19 + #endif /* SQL_CONST_INCLUDED */ diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index c7a0f9186e2..93344956468 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -21,6 +21,7 @@ #include "sql_view.h" // for make_valid_column_names #include "sql_parse.h" #include "sql_select.h" +#include "sql_show.h" // append_definer, append_identifier /** @@ -944,9 +945,9 @@ err: false otherwise */ -bool -With_element::rename_columns_of_derived_unit(THD *thd, - st_select_lex_unit *unit) +bool +With_element::process_columns_of_derived_unit(THD *thd, + st_select_lex_unit *unit) { if (unit->columns_are_renamed) return false; @@ -973,7 +974,7 @@ With_element::rename_columns_of_derived_unit(THD *thd, while ((item= it++, name= nm++)) { item->set_name(thd, *name); - item->is_autogenerated_name= false; + item->common_flags&= ~IS_AUTO_GENERATED_NAME; } if (arena) @@ -982,6 +983,43 @@ With_element::rename_columns_of_derived_unit(THD *thd, else make_valid_column_names(thd, select->item_list); + if (cycle_list) + { + List_iterator_fast<Item> it(select->item_list); + List_iterator_fast<Lex_ident_sys> nm(*cycle_list); + List_iterator_fast<Lex_ident_sys> nm_check(*cycle_list); + DBUG_ASSERT(cycle_list->elements != 0); + while (LEX_CSTRING *name= nm++) + { + Item *item; + /* + Check for uniqueness of each element in the cycle list: + It's sufficient to check that there is no duplicate of 'name' + among the elements that precede it. + */ + LEX_CSTRING *check; + nm_check.rewind(); + while ((check= nm_check++) && check != name) + { + if (check->length == name->length && + strncmp(check->str, name->str, name->length) == 0) + { + my_error(ER_DUP_FIELDNAME, MYF(0), check->str); + return true; + } + } + /* Check that 'name' is the name of a column of the processed CTE */ + while ((item= it++) && + (item->name.length != name->length || + strncmp(item->name.str, name->str, name->length) != 0)); + if (item == NULL) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), name->str, "CYCLE clause"); + return true; + } + item->common_flags|= IS_IN_WITH_CYCLE; + } + } unit->columns_are_renamed= true; return false; @@ -1018,7 +1056,7 @@ bool With_element::prepare_unreferenced(THD *thd) thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; if (!spec->prepared && (spec->prepare(spec->derived, 0, 0) || - rename_columns_of_derived_unit(thd, spec) || + process_columns_of_derived_unit(thd, spec) || check_duplicate_names(thd, first_sl->item_list, 1))) rc= true; @@ -1394,16 +1432,17 @@ bool st_select_lex::check_subqueries_with_recursive_references() /** @brief Print this with clause - + + @param thd Thread handle @param str Where to print to - @param query_type The mode of printing - + @param query_type The mode of printing + @details - The method prints a string representation of this clause in the + The method prints a string representation of this clause in the string str. The parameter query_type specifies the mode of printing. -*/ +*/ -void With_clause::print(String *str, enum_query_type query_type) +void With_clause::print(THD *thd, String *str, enum_query_type query_type) { /* Any with clause contains just definitions of CTE tables. @@ -1420,7 +1459,22 @@ void With_clause::print(String *str, enum_query_type query_type) { if (with_elem != with_list.first) str->append(", "); - with_elem->print(str, query_type); + with_elem->print(thd, str, query_type); + } +} + + +static void list_strlex_print(THD *thd, String *str, List<Lex_ident_sys> *list) +{ + List_iterator_fast<Lex_ident_sys> li(*list); + bool first= TRUE; + while(Lex_ident_sys *col_name= li++) + { + if (first) + first= FALSE; + else + str->append(','); + append_identifier(thd, str, col_name); } } @@ -1428,38 +1482,37 @@ void With_clause::print(String *str, enum_query_type query_type) /** @brief Print this with element - + + @param thd Thread handle @param str Where to print to - @param query_type The mode of printing - + @param query_type The mode of printing + @details - The method prints a string representation of this with element in the + The method prints a string representation of this with element in the string str. The parameter query_type specifies the mode of printing. */ -void With_element::print(String *str, enum_query_type query_type) +void With_element::print(THD *thd, String *str, enum_query_type query_type) { str->append(query_name); if (column_list.elements) { List_iterator_fast<Lex_ident_sys> li(column_list); str->append('('); - for (LEX_CSTRING *col_name= li++; ; ) - { - str->append(col_name); - col_name= li++; - if (!col_name) - { - str->append(')'); - break; - } - str->append(','); - } + list_strlex_print(thd, str, &column_list); + str->append(')'); } - str->append(STRING_WITH_LEN(" as ")); - str->append('('); + str->append(STRING_WITH_LEN(" as (")); spec->print(str, query_type); str->append(')'); + + if (cycle_list) + { + DBUG_ASSERT(cycle_list->elements != 0); + str->append(STRING_WITH_LEN(" CYCLE ")); + list_strlex_print(thd, str, cycle_list); + str->append(STRING_WITH_LEN(" RESTRICT ")); + } } @@ -1483,3 +1536,26 @@ bool With_element::instantiate_tmp_tables() return false; } +void With_element::set_cycle_list(List<Lex_ident_sys> *cycle_list_arg) +{ + cycle_list= cycle_list_arg; + + /* + If a CTE table with columns c1,...,cn is defined with a cycle + clause CYCLE(ci1,...,cik) then no two rows r1 and r2 from the + table shall have r1.ci1=r2.ci1 && ... && r1.cik=r2.cik. + + If a cycle clause is used in the specification of a CTE then + each UNION ALL at the top level of the specification is interpreted + as a UNION DISTINCT over the cycle columns. + */ + for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select()) + { + spec->union_distinct= sl; + if (sl != spec->first_select()) + { + sl->distinct= TRUE; + sl->with_all_modifier= FALSE; + } + } +} diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 92aca5090f3..4c42dd23614 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -112,6 +112,7 @@ public: always empty. */ List <Lex_ident_sys> column_list; + List <Lex_ident_sys> *cycle_list; /* The query that specifies the table introduced by this with element */ st_select_lex_unit *spec; /* @@ -169,7 +170,7 @@ public: sq_dep_map(0), work_dep_map(0), mutually_recursive(0), top_level_dep_map(0), sq_rec_ref(NULL), next_mutually_recursive(NULL), references(0), - query_name(name), column_list(list), spec(unit), + query_name(name), column_list(list), cycle_list(0), spec(unit), is_recursive(false), rec_outer_references(0), with_anchor(false), level(0), rec_result(NULL) { unit->with_element= this; } @@ -206,7 +207,7 @@ public: void inc_references() { references++; } - bool rename_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit); + bool process_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit); bool prepare_unreferenced(THD *thd); @@ -214,7 +215,7 @@ public: table_map &unrestricted, table_map &encountered); - void print(String *str, enum_query_type query_type); + void print(THD *thd, String *str, enum_query_type query_type); With_clause *get_owner() { return owner; } @@ -259,6 +260,8 @@ public: void prepare_for_next_iteration(); + void set_cycle_list(List<Lex_ident_sys> *cycle_list_arg); + friend class With_clause; }; @@ -353,7 +356,7 @@ public: void add_unrestricted(table_map map) { unrestricted|= map; } - void print(String *str, enum_query_type query_type); + void print(THD *thd, String *str, enum_query_type query_type); friend class With_element; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index ae7f26370fa..3ad7bea5661 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -186,9 +186,9 @@ bool my_dboptions_cache_init(void) if (!dboptions_init) { dboptions_init= 1; - error= my_hash_init(&dboptions, table_alias_charset, - 32, 0, 0, (my_hash_get_key) dboptions_get_key, - free_dbopt,0); + error= my_hash_init(key_memory_dboptions_hash, &dboptions, + table_alias_charset, 32, 0, 0, (my_hash_get_key) + dboptions_get_key, free_dbopt, 0); } return error; } @@ -218,9 +218,8 @@ void my_dbopt_cleanup(void) { mysql_rwlock_wrlock(&LOCK_dboptions); my_hash_free(&dboptions); - my_hash_init(&dboptions, table_alias_charset, - 32, 0, 0, (my_hash_get_key) dboptions_get_key, - free_dbopt,0); + my_hash_init(key_memory_dboptions_hash, &dboptions, table_alias_charset, 32, + 0, 0, (my_hash_get_key) dboptions_get_key, free_dbopt, 0); mysql_rwlock_unlock(&LOCK_dboptions); } @@ -290,7 +289,7 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create) /* Options are not in the hash, insert them */ char *tmp_name; char *tmp_comment= NULL; - if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + if (!my_multi_malloc(key_memory_dboptions_hash, MYF(MY_WME | MY_ZEROFILL), &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1, &tmp_comment, (uint) DATABASE_COMMENT_MAXLEN+1, NullS)) @@ -1148,9 +1147,9 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp, (char*) table_list->table_name.str); table_list->alias= table_list->table_name; // If lower_case_table_names=2 - table_list->mdl_request.init(MDL_key::TABLE, table_list->db.str, - table_list->table_name.str, MDL_EXCLUSIVE, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE, + table_list->db.str, table_list->table_name.str, + MDL_EXCLUSIVE, MDL_TRANSACTION); /* Link into list */ (*tot_list_next_local)= table_list; (*tot_list_next_global)= table_list; @@ -1547,8 +1546,8 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, TODO: fix check_db_name(). */ - new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length, - MYF(MY_WME)); + new_db_file_name.str= my_strndup(key_memory_THD_db, new_db_name->str, + new_db_name->length, MYF(MY_WME)); new_db_file_name.length= new_db_name->length; if (new_db_file_name.str == NULL) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 6a4ce266af2..bef77e1a2e9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -30,7 +30,6 @@ #include "lock.h" // unlock_table_name #include "sql_view.h" // check_key_in_view, mysql_frm_type #include "sql_parse.h" // mysql_init_select -#include "sql_acl.h" // *_ACL #include "filesort.h" // filesort #include "sql_handler.h" // mysql_ha_rm_tables #include "sql_select.h" diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index c713f1322dc..7d09c85a7c7 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -816,8 +816,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) if ((res= unit->prepare(derived, derived->derived_result, 0))) goto exit; if (derived->with && - (res= derived->with->rename_columns_of_derived_unit(thd, unit))) - goto exit; + (res= derived->with->process_columns_of_derived_unit(thd, unit))) + goto exit; lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; if ((res= check_duplicate_names(thd, unit->types, 0))) goto exit; diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 7e6ffb67b94..4045f30a6bd 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -506,7 +506,7 @@ void Warning_info::init() { /* Initialize sub structures */ DBUG_ASSERT(initialized == 0); - init_sql_alloc(&m_warn_root, "Warning_info", WARN_ALLOC_BLOCK_SIZE, + init_sql_alloc(PSI_INSTRUMENT_ME, &m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE, MYF(MY_THREAD_SPECIFIC)); initialized= 1; } diff --git a/sql/sql_explain.h b/sql/sql_explain.h index bd8c8a4d499..041f77b6f42 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -342,7 +342,7 @@ class Explain_union : public Explain_node { public: Explain_union(MEM_ROOT *root, bool is_analyze) : - Explain_node(root), + Explain_node(root), union_members(PSI_INSTRUMENT_MEM), is_recursive_cte(false), fake_select_lex_explain(root, is_analyze) {} diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 12119997430..d7adc35c5c9 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -289,10 +289,11 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) /* HASH entries are of type SQL_HANDLER */ - if (my_hash_init(&thd->handler_tables_hash, &my_charset_latin1, - HANDLER_TABLES_HASH_SIZE, 0, 0, - (my_hash_get_key) mysql_ha_hash_get_key, - (my_hash_free_key) mysql_ha_hash_free, 0)) + if (my_hash_init(key_memory_THD_handler_tables_hash, + &thd->handler_tables_hash, &my_charset_latin1, + HANDLER_TABLES_HASH_SIZE, 0, 0, (my_hash_get_key) + mysql_ha_hash_get_key, (my_hash_free_key) + mysql_ha_hash_free, 0)) { DBUG_PRINT("exit",("ERROR")); DBUG_RETURN(TRUE); @@ -332,8 +333,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) right from the start as open_tables() can't handle properly back-off for such locks. */ - tables->mdl_request.init(MDL_key::TABLE, tables->db.str, tables->table_name.str, - MDL_SHARED_READ, MDL_TRANSACTION); + MDL_REQUEST_INIT(&tables->mdl_request, MDL_key::TABLE, tables->db.str, + tables->table_name.str, MDL_SHARED_READ, MDL_TRANSACTION); mdl_savepoint= thd->mdl_context.mdl_savepoint(); /* for now HANDLER can be used only for real TABLES */ @@ -384,14 +385,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) /* copy data to sql_handler */ if (!(sql_handler= new SQL_HANDLER(thd))) goto err; - init_alloc_root(&sql_handler->mem_root, "sql_handler", 1024, 0, + init_alloc_root(PSI_INSTRUMENT_ME, &sql_handler->mem_root, 1024, 0, MYF(MY_THREAD_SPECIFIC)); sql_handler->db.length= tables->db.length; sql_handler->table_name.length= tables->table_name.length; sql_handler->handler_name.length= tables->alias.length; - if (!(my_multi_malloc(MY_WME, + if (!(my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &sql_handler->base_data, (uint) sql_handler->db.length + 1, &sql_handler->table_name.str, diff --git a/sql/sql_hset.h b/sql/sql_hset.h index aaecef9f0d4..b3d8165f6f6 100644 --- a/sql/sql_hset.h +++ b/sql/sql_hset.h @@ -31,18 +31,19 @@ public: Constructs an empty hash. Does not allocate memory, it is done upon the first insert. Thus does not cause or return errors. */ - Hash_set(uchar *(*K)(const T *, size_t *, my_bool), + Hash_set(PSI_memory_key psi_key, uchar *(*K)(const T *, size_t *, my_bool), CHARSET_INFO *cs= &my_charset_bin) { my_hash_clear(&m_hash); m_hash.get_key= (my_hash_get_key)K; m_hash.charset= cs; + m_hash.array.m_psi_key= psi_key; } - Hash_set(CHARSET_INFO *charset, ulong default_array_elements, + Hash_set(PSI_memory_key psi_key, CHARSET_INFO *charset, ulong default_array_elements, size_t key_offset, size_t key_length, my_hash_get_key get_key, void (*free_element)(void*), uint flags) { - my_hash_init(&m_hash, charset, default_array_elements, key_offset, + my_hash_init(psi_key, &m_hash, charset, default_array_elements, key_offset, key_length, get_key, free_element, flags); } /** @@ -64,8 +65,8 @@ public: */ bool insert(T *value) { - my_hash_init_opt(&m_hash, m_hash.charset, START_SIZE, 0, 0, - m_hash.get_key, 0, HASH_UNIQUE); + my_hash_init_opt(m_hash.array.m_psi_key, &m_hash, m_hash.charset, + START_SIZE, 0, 0, m_hash.get_key, 0, HASH_UNIQUE); return my_hash_insert(&m_hash, reinterpret_cast<const uchar*>(value)); } bool remove(T *value) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 60b60ec1e54..708423c6214 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -67,7 +67,6 @@ #include "sp_head.h" #include "sql_view.h" // check_key_in_view, insert_view_fields #include "sql_table.h" // mysql_create_table_no_lock -#include "sql_acl.h" // *_ACL, check_grant_all_columns #include "sql_trigger.h" #include "sql_select.h" #include "sql_show.h" @@ -554,8 +553,8 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) if (thd->has_read_only_protection()) DBUG_RETURN(TRUE); - protection_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DML, - MDL_STATEMENT); + MDL_REQUEST_INIT(&protection_request, MDL_key::BACKUP, "", "", + MDL_BACKUP_DML, MDL_STATEMENT); if (thd->mdl_context.acquire_lock(&protection_request, thd->variables.lock_wait_timeout)) @@ -2402,7 +2401,8 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, di->thd.variables.binlog_annotate_row_events= 0; di->thd.set_db(&table_list->db); - di->thd.set_query(my_strndup(table_list->table_name.str, + di->thd.set_query(my_strndup(PSI_INSTRUMENT_ME, + table_list->table_name.str, table_list->table_name.length, MYF(MY_WME | ME_FATAL)), table_list->table_name.length, system_charset_info); @@ -2421,8 +2421,8 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, We need the tickets so that they can be cloned in handle_delayed_insert */ - di->grl_protection.init(MDL_key::BACKUP, "", "", - MDL_BACKUP_DML, MDL_STATEMENT); + MDL_REQUEST_INIT(&di->grl_protection, MDL_key::BACKUP, "", "", + MDL_BACKUP_DML, MDL_STATEMENT); di->grl_protection.ticket= grl_protection_request->ticket; init_mdl_requests(&di->table_list); di->table_list.mdl_request.ticket= table_list->mdl_request.ticket; @@ -2731,7 +2731,8 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, if (query.str) { char *str; - if (!(str= my_strndup(query.str, query.length, MYF(MY_WME)))) + if (!(str= my_strndup(PSI_INSTRUMENT_ME, query.str, query.length, + MYF(MY_WME)))) goto err; query.str= str; } @@ -2754,7 +2755,8 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, ip_len= strlen(thd->security_ctx->ip) + 1; } /* This can't be THREAD_SPECIFIC as it's freed in delayed thread */ - if (!(row->record= (char*) my_malloc(table->s->reclength + + if (!(row->record= (char*) my_malloc(PSI_INSTRUMENT_ME, + table->s->reclength + user_len + host_len + ip_len, MYF(MY_WME)))) goto err; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 3a509b3d750..b3d0d985582 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -937,7 +937,8 @@ int JOIN_CACHE::alloc_buffer() { size_t next_buff_size; - if ((buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC)))) + if ((buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size, + MYF(MY_THREAD_SPECIFIC)))) break; next_buff_size= buff_size > buff_size_decr ? buff_size-buff_size_decr : 0; @@ -1013,11 +1014,11 @@ bool JOIN_CACHE::shrink_join_buffer_in_ratio(ulonglong n, ulonglong d) int JOIN_CACHE::realloc_buffer() { - int rc; free(); - rc= MY_TEST(!(buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC)))); + buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size, + MYF(MY_THREAD_SPECIFIC)); reset(TRUE); - return rc; + return buff == NULL; } @@ -2084,8 +2085,13 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last) if (!join_tab->first_unmatched) { + bool pfs_batch_update= join_tab->pfs_batch_update(join); + if (pfs_batch_update) + join_tab->table->file->start_psi_batch_mode(); /* Find all records from join_tab that match records from join buffer */ rc= join_matching_records(skip_last); + if (pfs_batch_update) + join_tab->table->file->end_psi_batch_mode(); if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) goto finish; if (outer_join_first_inner) @@ -2809,12 +2815,12 @@ int JOIN_CACHE_HASHED::init_hash_table() int JOIN_CACHE_HASHED::realloc_buffer() { - int rc; free(); - rc= MY_TEST(!(buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC)))); + buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size, + MYF(MY_THREAD_SPECIFIC)); init_hash_table(); reset(TRUE); - return rc; + return buff == NULL; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ea60d0cebd0..da255c2701d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -511,7 +511,7 @@ void LEX::add_key_to_list(LEX_CSTRING *field_name, } -bool LEX::add_alter_list(const char *name, Virtual_column_info *expr, +bool LEX::add_alter_list(LEX_CSTRING name, Virtual_column_info *expr, bool exists) { MEM_ROOT *mem_root= thd->mem_root; @@ -524,6 +524,17 @@ bool LEX::add_alter_list(const char *name, Virtual_column_info *expr, } +bool LEX::add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name) +{ + Alter_column *ac= new (thd->mem_root) Alter_column(name, new_name); + if (unlikely(ac == NULL)) + return true; + alter_info.alter_list.push_back(ac, thd->mem_root); + alter_info.flags|= ALTER_RENAME_COLUMN; + return false; +} + + void LEX::init_last_field(Column_definition *field, const LEX_CSTRING *field_name, const CHARSET_INFO *cs) @@ -3503,10 +3514,74 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) } +/* + @brief + Print the whole statement + + @param str Print into this string + @param query_type Flags describing how to print + + @detail + The intent is to allow to eventually print back any query. + + This is useful e.g. for storage engines that take over diferrent kinds of + queries +*/ + +void LEX::print(String *str, enum_query_type query_type) +{ + if (sql_command == SQLCOM_UPDATE) + { + SELECT_LEX *sel= first_select_lex(); + str->append(STRING_WITH_LEN("UPDATE ")); + if (ignore) + str->append(STRING_WITH_LEN("IGNORE ")); + // table name + str->append(query_tables->alias); + str->append(STRING_WITH_LEN(" SET ")); + // print item assignments + List_iterator<Item> it(sel->item_list); + List_iterator<Item> it2(value_list); + Item *col_ref, *value; + bool first= true; + while ((col_ref= it++) && (value= it2++)) + { + if (first) + first= false; + else + str->append(STRING_WITH_LEN(", ")); + col_ref->print(str, query_type); + str->append(STRING_WITH_LEN("=")); + value->print(str, query_type); + } + + str->append(STRING_WITH_LEN(" WHERE ")); + sel->where->print(str, query_type); + + if (sel->order_list.elements) + { + str->append(STRING_WITH_LEN(" ORDER BY ")); + for (ORDER *ord= sel->order_list.first; ord; ord= ord->next) + { + if (ord != sel->order_list.first) + str->append(STRING_WITH_LEN(", ")); + (*ord->item)->print(str, query_type); + } + } + if (sel->select_limit) + { + str->append(STRING_WITH_LEN(" LIMIT ")); + sel->select_limit->print(str, query_type); + } + } + else + DBUG_ASSERT(0); // Not implemented yet +} + void st_select_lex_unit::print(String *str, enum_query_type query_type) { if (with_clause) - with_clause->print(str, query_type); + with_clause->print(thd, str, query_type); for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { if (sl != first_select()) @@ -3751,12 +3826,12 @@ LEX::LEX() default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX) { - init_dynamic_array2(&plugins, sizeof(plugin_ref), plugins_static_buffer, - INITIAL_LEX_PLUGIN_LIST_SIZE, + init_dynamic_array2(PSI_INSTRUMENT_ME, &plugins, sizeof(plugin_ref), + plugins_static_buffer, INITIAL_LEX_PLUGIN_LIST_SIZE, INITIAL_LEX_PLUGIN_LIST_SIZE, 0); reset_query_tables_list(TRUE); mi.init(); - init_dynamic_array2(&delete_gtid_domain, sizeof(uint32), + init_dynamic_array2(PSI_INSTRUMENT_ME, &delete_gtid_domain, sizeof(uint32), gtid_domain_static_buffer, initial_gtid_domain_buffer_size, initial_gtid_domain_buffer_size, 0); @@ -5584,8 +5659,8 @@ bool LEX::set_arena_for_set_stmt(Query_arena *backup) mem_root_for_set_stmt= new MEM_ROOT(); if (unlikely(!(mem_root_for_set_stmt))) DBUG_RETURN(1); - init_sql_alloc(mem_root_for_set_stmt, "set_stmt", - ALLOC_ROOT_SET, ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(PSI_INSTRUMENT_ME, mem_root_for_set_stmt, ALLOC_ROOT_SET, + ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC)); } if (unlikely(!(arena_for_set_stmt= new(mem_root_for_set_stmt) Query_arena_memroot(mem_root_for_set_stmt, @@ -6181,7 +6256,7 @@ static bool is_old(const char *str) bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name) const { // "name" is not necessarily NULL-terminated! - return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER && + return sphead && sphead->m_handler->type() == SP_TYPE_TRIGGER && name->length == 3 && (is_new(name->str) || is_old(name->str)); } @@ -8934,7 +9009,7 @@ sp_package *LEX::create_package_start(THD *thd, } if (unlikely(set_command_with_check(command, options))) return NULL; - if (sph->type() == TYPE_ENUM_PACKAGE_BODY) + if (sph->type() == SP_TYPE_PACKAGE_BODY) { /* If we start parsing a "CREATE PACKAGE BODY", we need to load diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2d08aa6c79b..b2f0272a7d2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -30,7 +30,7 @@ #include "sql_alter.h" // Alter_info #include "sql_window.h" #include "sql_trigger.h" -#include "sp.h" // enum stored_procedure_type +#include "sp.h" // enum enum_sp_type #include "sql_tvc.h" #include "item.h" #include "sql_limit.h" // Select_limit_counters @@ -510,11 +510,11 @@ struct LEX_MASTER_INFO void init() { bzero(this, sizeof(*this)); - my_init_dynamic_array(&repl_ignore_server_ids, + my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_server_ids, sizeof(::server_id), 0, 16, MYF(0)); - my_init_dynamic_array(&repl_do_domain_ids, + my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_do_domain_ids, sizeof(ulong), 0, 16, MYF(0)); - my_init_dynamic_array(&repl_ignore_domain_ids, + my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_domain_ids, sizeof(ulong), 0, 16, MYF(0)); sql_delay= -1; } @@ -3264,6 +3264,7 @@ public: void reset_arena_for_set_stmt(Query_arena *backup); void free_arena_for_set_stmt(); + void print(String *str, enum_query_type qtype); List<Item_func_set_user_var> set_var_list; // in-query assignment list List<Item_param> param_list; List<LEX_CSTRING> view_list; // view list (list of field names in view) @@ -4320,8 +4321,9 @@ public: alter_info.check_constraint_list.push_back(constr); return false; } - bool add_alter_list(const char *par_name, Virtual_column_info *expr, + bool add_alter_list(LEX_CSTRING par_name, Virtual_column_info *expr, bool par_exists); + bool add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name); void set_command(enum_sql_command command, DDL_options_st options) { diff --git a/sql/sql_list.h b/sql/sql_list.h index 9d1c01a484d..91134bcbeb2 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -677,7 +677,8 @@ struct ilink struct ilink **prev,*next; static void *operator new(size_t size) throw () { - return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATAL)); + return (void*)my_malloc(PSI_INSTRUMENT_ME, + (uint)size, MYF(MY_WME | MY_FAE | ME_FATAL)); } static void operator delete(void* ptr_arg, size_t) { diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index 2ad8d8a914a..a3d1a7242e4 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -51,7 +51,8 @@ bool mysql_manager_submit(void (*action)()) cb= &(*cb)->next; if (!*cb) { - *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME)); + *cb= (struct handler_cb *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(struct handler_cb), MYF(MY_WME)); if (!*cb) result= TRUE; else diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dac5b025821..cb0d210b12c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -56,13 +56,6 @@ #include "sql_rename.h" // mysql_rename_tables #include "sql_tablespace.h" // mysql_alter_tablespace #include "hostname.h" // hostname_cache_refresh -#include "sql_acl.h" // *_ACL, check_grant, is_acl_user, - // has_any_table_level_privileges, - // mysql_drop_user, mysql_rename_user, - // check_grant_routine, - // mysql_routine_grant, - // mysql_show_grants, - // sp_grant_privileges, ... #include "sql_test.h" // mysql_print_status #include "sql_select.h" // handle_select, mysql_select, // mysql_explain_union @@ -101,6 +94,7 @@ #include "sql_bootstrap.h" #include "sql_sequence.h" #include "opt_trace.h" +#include "mysql/psi/mysql_sp.h" #include "my_json_writer.h" @@ -679,7 +673,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_BINLOG_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; @@ -1010,7 +1004,8 @@ int bootstrap(MYSQL_FILE *file) thd->thread_stack= (char*) &thd; thd->store_globals(); - thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); + thd->security_ctx->user= (char*) my_strdup(key_memory_MPVIO_EXT_auth_info, + "boot", MYF(MY_WME)); thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]= thd->security_ctx->priv_role[0]= 0; /* @@ -1404,7 +1399,7 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) LEX *lex= thd->lex; /* Super user is allowed to do changes */ - if ((thd->security_ctx->master_access & SUPER_ACL) == SUPER_ACL) + if ((thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) != NO_ACL) DBUG_RETURN(FALSE); /* Check if command doesn't update anything */ @@ -1444,10 +1439,10 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables) { int opt_readonly_saved = opt_readonly; - privilege_t flag_saved= thd->security_ctx->master_access & SUPER_ACL; + privilege_t flag_saved= thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY; opt_readonly = 0; - thd->security_ctx->master_access &= ~SUPER_ACL; + thd->security_ctx->master_access &= ~PRIV_IGNORE_READ_ONLY; my_bool ret = !deny_updates_if_read_only_option(thd, all_tables); @@ -1464,7 +1459,7 @@ static void wsrep_copy_query(THD *thd) if (thd->wsrep_retry_query) { my_free(thd->wsrep_retry_query); } - thd->wsrep_retry_query = (char *)my_malloc( + thd->wsrep_retry_query = (char *)my_malloc(PSI_INSTRUMENT_ME, thd->wsrep_retry_query_len + 1, MYF(0)); strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len); thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0'; @@ -1908,8 +1903,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, com_statement_info[command].m_key, thd->db.str, thd->db.length, - thd->charset()); - THD_STAGE_INFO(thd, stage_init); + thd->charset(), NULL); + THD_STAGE_INFO(thd, stage_starting); MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt, length); @@ -2091,7 +2086,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, status_var_increment(thd->status_var.com_other); thd->query_plan_flags|= QPLAN_ADMIN; - if (check_global_access(thd, REPL_SLAVE_ACL)) + if (check_global_access(thd, PRIV_COM_BINLOG_DUMP)) break; /* TODO: The following has to be changed to an 8 byte integer */ @@ -2247,12 +2242,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_PROCESS_INFO: status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]); if (!thd->security_ctx->priv_user[0] && - check_global_access(thd, PROCESS_ACL)) + check_global_access(thd, PRIV_COM_PROCESS_INFO)) break; general_log_print(thd, command, NullS); mysqld_list_processes(thd, - thd->security_ctx->master_access & PROCESS_ACL ? - NullS : thd->security_ctx->priv_user, 0); + thd->security_ctx->master_access & PRIV_COM_PROCESS_INFO ? + NullS : thd->security_ctx->priv_user, 0); break; case COM_PROCESS_KILL: { @@ -2284,7 +2279,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_DEBUG: status_var_increment(thd->status_var.com_other); - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_DEBUG)) break; /* purecov: inspected */ mysql_print_status(); general_log_print(thd, command, NullS); @@ -2838,7 +2833,7 @@ bool sp_process_definer(THD *thd) !my_strcasecmp(system_charset_info, d->host.str, thd->security_ctx->priv_host); if (!curuserhost && !currole && - check_global_access(thd, SUPER_ACL, false)) + check_global_access(thd, PRIV_DEFINER_CLAUSE, false)) DBUG_RETURN(TRUE); } @@ -3062,7 +3057,7 @@ mysql_create_routine(THD *thd, LEX *lex) const LEX_CSTRING *name= lex->sphead->name(); #ifdef HAVE_DLOPEN - if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION) + if (lex->sphead->m_handler->type() == SP_TYPE_FUNCTION) { udf_func *udf = find_udf(name->str, name->length); @@ -3826,7 +3821,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_EXPLAIN: { if (!thd->security_ctx->priv_user[0] && - check_global_access(thd,PROCESS_ACL)) + check_global_access(thd, PRIV_STMT_SHOW_EXPLAIN)) break; /* @@ -3944,7 +3939,7 @@ mysql_execute_command(THD *thd) #ifndef EMBEDDED_LIBRARY case SQLCOM_PURGE: { - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG)) goto error; /* PURGE MASTER LOGS TO 'file' */ res = purge_master_logs(thd, lex->to_log); @@ -3954,7 +3949,7 @@ mysql_execute_command(THD *thd) { Item *it; - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG)) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); @@ -4001,16 +3996,23 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION case SQLCOM_SHOW_SLAVE_HOSTS: { - if (check_global_access(thd, REPL_SLAVE_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_SLAVE_HOSTS)) goto error; res = show_slave_hosts(thd); break; } - case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */ + case SQLCOM_SHOW_RELAYLOG_EVENTS: + { + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); + if (check_global_access(thd, PRIV_STMT_SHOW_RELAYLOG_EVENTS)) + goto error; + res = mysql_show_binlog_events(thd); + break; + } case SQLCOM_SHOW_BINLOG_EVENTS: { WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (check_global_access(thd, REPL_SLAVE_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_EVENTS)) goto error; res = mysql_show_binlog_events(thd); break; @@ -4047,7 +4049,7 @@ mysql_execute_command(THD *thd) bool new_master= 0; bool master_info_added; - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_CHANGE_MASTER)) goto error; /* In this code it's ok to use LOCK_active_mi as we are adding new things @@ -4102,10 +4104,10 @@ mysql_execute_command(THD *thd) break; } - case SQLCOM_SHOW_MASTER_STAT: + case SQLCOM_SHOW_BINLOG_STAT: { /* Accept one of two privileges */ - if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_STATUS)) goto error; res = show_binlog_info(thd); break; @@ -4114,14 +4116,14 @@ mysql_execute_command(THD *thd) #endif /* HAVE_REPLICATION */ case SQLCOM_SHOW_ENGINE_STATUS: { - if (check_global_access(thd, PROCESS_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_STATUS)) goto error; res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS); break; } case SQLCOM_SHOW_ENGINE_MUTEX: { - if (check_global_access(thd, PROCESS_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_MUTEX)) goto error; res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX); break; @@ -4282,7 +4284,7 @@ mysql_execute_command(THD *thd) goto error; #else { - if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) + if (check_global_access(thd, PRIV_STMT_SHOW_BINARY_LOGS)) goto error; WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); res = show_binlogs(thd); @@ -4414,7 +4416,7 @@ mysql_execute_command(THD *thd) if (res) break; if (opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && + !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && some_non_temp_table_to_be_updated(thd, all_tables)) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); @@ -4890,13 +4892,13 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROCESSLIST: if (!thd->security_ctx->priv_user[0] && - check_global_access(thd,PROCESS_ACL)) + check_global_access(thd, PRIV_STMT_SHOW_PROCESSLIST)) break; mysqld_list_processes(thd, - (thd->security_ctx->master_access & PROCESS_ACL ? - NullS : - thd->security_ctx->priv_user), - lex->verbose); + (thd->security_ctx->master_access & PRIV_STMT_SHOW_PROCESSLIST ? + NullS : + thd->security_ctx->priv_user), + lex->verbose); break; case SQLCOM_SHOW_AUTHORS: res= mysqld_show_authors(thd); @@ -4940,8 +4942,9 @@ mysql_execute_command(THD *thd) if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || !opt_local_infile) { - my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0)); - goto error; + my_message(ER_LOAD_INFILE_CAPABILITY_DISABLED, + ER_THD(thd, ER_LOAD_INFILE_CAPABILITY_DISABLED), MYF(0)); + goto error; } } @@ -5615,12 +5618,18 @@ mysql_execute_command(THD *thd) break; /* break super switch */ } /* end case group bracket */ case SQLCOM_COMPOUND: + { + sp_head *sp= lex->sphead; DBUG_ASSERT(all_tables == 0); DBUG_ASSERT(thd->in_sub_stmt == 0); - lex->sphead->m_sql_mode= thd->variables.sql_mode; + sp->m_sql_mode= thd->variables.sql_mode; + sp->m_sp_share= MYSQL_GET_SP_SHARE(sp->m_handler->type(), + sp->m_db.str, static_cast<uint>(sp->m_db.length), + sp->m_name.str, static_cast<uint>(sp->m_name.length)); if (do_execute_sp(thd, lex->sphead)) goto error; break; + } case SQLCOM_ALTER_PROCEDURE: case SQLCOM_ALTER_FUNCTION: @@ -5801,7 +5810,7 @@ mysql_execute_command(THD *thd) { DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER")); - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_CREATE_SERVER)) break; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); @@ -5814,7 +5823,7 @@ mysql_execute_command(THD *thd) int error; DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER")); - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_ALTER_SERVER)) break; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); @@ -5834,7 +5843,7 @@ mysql_execute_command(THD *thd) int err_code; DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER")); - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PRIV_STMT_DROP_SERVER)) break; WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); @@ -6179,6 +6188,7 @@ execute_show_status(THD *thd, TABLE_LIST *all_tables) UINT_MAX, FALSE))) res= execute_sqlcom_select(thd, all_tables); + thd->initial_status_var= NULL; /* Don't log SHOW STATUS commands to slow query log */ thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); @@ -7136,10 +7146,8 @@ bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table) @param want_access Use should have any of these global rights @warning - One gets access right if one has ANY of the rights in want_access. - This is useful as one in most cases only need one global right, - but in some case we want to check if the user has SUPER or - REPL_CLIENT_ACL rights. + Starting from 10.5.2 only one bit is allowed in want_access. + Access denied error is returned if want_access has multiple bits set. @retval 0 ok @@ -7151,7 +7159,7 @@ bool check_global_access(THD *thd, privilege_t want_access, bool no_errors) { #ifndef NO_EMBEDDED_ACCESS_CHECKS char command[128]; - if ((thd->security_ctx->master_access & want_access)) + if (thd->security_ctx->master_access & want_access) return 0; if (unlikely(!no_errors)) { @@ -7365,11 +7373,11 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, size_t *yystacksize) old_info= *yystacksize; *yystacksize= set_zone((int)(*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); if (!(state->yacc_yyvs= (uchar*) - my_realloc(state->yacc_yyvs, + my_realloc(key_memory_bison_stack, state->yacc_yyvs, *yystacksize*sizeof(**yyvs), MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) || !(state->yacc_yyss= (uchar*) - my_realloc(state->yacc_yyss, + my_realloc(key_memory_bison_stack, state->yacc_yyss, *yystacksize*sizeof(**yyss), MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR)))) return 1; @@ -8219,9 +8227,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, // Pure table aliases do not need to be locked: if (ptr->db.str && !(table_options & TL_OPTION_ALIAS)) { - ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str, - mdl_type, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&ptr->mdl_request, MDL_key::TABLE, ptr->db.str, + ptr->table_name.str, mdl_type, MDL_TRANSACTION); } DBUG_RETURN(ptr); } @@ -9090,11 +9097,11 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ */ #ifdef WITH_WSREP - if (((thd->security_ctx->master_access & SUPER_ACL) || + if (((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) || thd->security_ctx->user_matches(tmp->security_ctx)) && !wsrep_thd_is_BF(tmp, false) && !tmp->wsrep_applier) #else - if ((thd->security_ctx->master_access & SUPER_ACL) || + if ((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) || thd->security_ctx->user_matches(tmp->security_ctx)) #endif /* WITH_WSREP */ { @@ -9147,7 +9154,8 @@ static my_bool kill_threads_callback(THD *thd, kill_threads_callback_arg *arg) !strcmp(thd->security_ctx->host_or_ip, arg->user->host.str)) && !strcmp(thd->security_ctx->user, arg->user->user.str)) { - if (!(arg->thd->security_ctx->master_access & SUPER_ACL) && + if (!(arg->thd->security_ctx->master_access & + PRIV_KILL_OTHER_USER_PROCESS) && !arg->thd->security_ctx->user_matches(thd->security_ctx)) return 1; if (!arg->threads_to_kill.push_back(thd, arg->thd->mem_root)) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 5885e3715bf..f722dc54fb4 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4805,7 +4805,6 @@ static void check_datadir_altered_for_innodb(THD *thd, uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, - Alter_table_ctx *alter_ctx, bool *partition_changed, bool *fast_alter_table) { @@ -4900,8 +4899,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, object to allow fast_alter_partition_table to perform the changes. */ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, - alter_ctx->db.str, - alter_ctx->table_name.str, + table->s->db.str, + table->s->table_name.str, MDL_INTENTION_EXCLUSIVE)); tab_part_info= table->part_info; @@ -7501,7 +7500,7 @@ void append_row_to_str(String &str, const uchar *row, TABLE *table) rec= row; /* Create a new array of all read fields. */ - fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1), + fields= (Field**) my_malloc(PSI_INSTRUMENT_ME, sizeof(void*) * (num_fields + 1), MYF(0)); if (!fields) return; diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 8732aacbbd7..58ba82dcd9f 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -262,7 +262,6 @@ bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info, enum partition_state part_state); uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, - Alter_table_ctx *alter_ctx, bool *partition_changed, bool *fast_alter_table); char *generate_partition_syntax(THD *thd, partition_info *part_info, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index bbfbdc3a22e..1d18b0ef392 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -28,7 +28,6 @@ #include "sql_table.h" #include "sql_show.h" // remove_status_vars, add_status_vars #include "strfunc.h" // find_set -#include "sql_acl.h" // *_ACL #include "records.h" // init_read_record, end_read_record #include <my_pthread.h> #include <my_getopt.h> @@ -42,6 +41,12 @@ #include <mysql/plugin_function.h> #include "sql_plugin_compat.h" +static PSI_memory_key key_memory_plugin_mem_root; +static PSI_memory_key key_memory_plugin_int_mem_root; +static PSI_memory_key key_memory_mysql_plugin; +static PSI_memory_key key_memory_mysql_plugin_dl; +static PSI_memory_key key_memory_plugin_bookmark; + #ifdef HAVE_LINK_H #include <link.h> #endif @@ -573,7 +578,7 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl, /* no op */; cur= (struct st_maria_plugin*) - my_malloc((i + 1) * sizeof(struct st_maria_plugin), + my_malloc(key_memory_mysql_plugin, (i + 1) * sizeof(struct st_maria_plugin), MYF(MY_ZEROFILL|MY_WME)); if (!cur) { @@ -693,7 +698,7 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl, /* no op */; cur= (struct st_maria_plugin*) - my_malloc((i + 1) * sizeof(struct st_maria_plugin), + my_malloc(key_memory_mysql_plugin, (i + 1) * sizeof(struct st_maria_plugin), MYF(MY_ZEROFILL|MY_WME)); if (!cur) { @@ -818,7 +823,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags) if (plugin_dl.nbackups) { size_t bytes= plugin_dl.nbackups * sizeof(plugin_dl.ptr_backup[0]); - plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(bytes, MYF(0)); + plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(key_memory_mysql_plugin_dl, + bytes, MYF(0)); if (!plugin_dl.ptr_backup) { restore_ptr_backup(plugin_dl.nbackups, tmp_backup); @@ -830,7 +836,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags) /* Duplicate and convert dll name */ plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1; - if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0)))) + if (! (plugin_dl.dl.str= (char*) my_malloc(key_memory_mysql_plugin_dl, + plugin_dl.dl.length, MYF(0)))) { my_error(ER_OUTOFMEMORY, MyFlags, static_cast<int>(plugin_dl.dl.length)); @@ -977,7 +984,8 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc, memory manager and/or valgrind to track locked references and double unlocks to aid resolving reference counting problems. */ - if (!(plugin= (plugin_ref) my_malloc(sizeof(pi), MYF(MY_WME)))) + if (!(plugin= (plugin_ref) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(pi), + MYF(MY_WME)))) DBUG_RETURN(NULL); *plugin= pi; @@ -1186,7 +1194,8 @@ static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists, goto err; if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr)) tmp_plugin_ptr->state= PLUGIN_IS_FREED; - init_alloc_root(&tmp_plugin_ptr->mem_root, "plugin", 4096, 4096, MYF(0)); + init_alloc_root(key_memory_plugin_int_mem_root, &tmp_plugin_ptr->mem_root, + 4096, 4096, MYF(0)); if (name->str) DBUG_RETURN(INSTALL_GOOD); // all done @@ -1541,6 +1550,15 @@ static PSI_mutex_info all_plugin_mutexes[]= { &key_LOCK_plugin, "LOCK_plugin", PSI_FLAG_GLOBAL} }; +static PSI_memory_info all_plugin_memory[]= +{ + { &key_memory_plugin_mem_root, "plugin_mem_root", PSI_FLAG_GLOBAL}, + { &key_memory_plugin_int_mem_root, "plugin_int_mem_root", 0}, + { &key_memory_mysql_plugin_dl, "mysql_plugin_dl", 0}, + { &key_memory_mysql_plugin, "mysql_plugin", 0}, + { &key_memory_plugin_bookmark, "plugin_bookmark", PSI_FLAG_GLOBAL} +}; + static void init_plugin_psi_keys(void) { const char* category= "sql"; @@ -1551,7 +1569,12 @@ static void init_plugin_psi_keys(void) count= array_elements(all_plugin_mutexes); PSI_server->register_mutex(category, all_plugin_mutexes, count); + + count= array_elements(all_plugin_memory); + mysql_memory_register(category, all_plugin_memory, count); } +#else +static void init_plugin_psi_keys(void) {} #endif /* HAVE_PSI_INTERFACE */ /* @@ -1578,11 +1601,13 @@ int plugin_init(int *argc, char **argv, int flags) dlopen_count =0; - init_alloc_root(&plugin_mem_root, "plugin", 4096, 4096, MYF(0)); - init_alloc_root(&plugin_vars_mem_root, "plugin_vars", 4096, 4096, MYF(0)); - init_alloc_root(&tmp_root, "plugin_tmp", 4096, 4096, MYF(0)); + init_plugin_psi_keys(); + + init_alloc_root(key_memory_plugin_mem_root, &plugin_mem_root, 4096, 4096, MYF(0)); + init_alloc_root(key_memory_plugin_mem_root, &plugin_vars_mem_root, 4096, 4096, MYF(0)); + init_alloc_root(PSI_NOT_INSTRUMENTED, &tmp_root, 4096, 4096, MYF(0)); - if (my_hash_init(&bookmark_hash, &my_charset_bin, 32, 0, 0, + if (my_hash_init(key_memory_plugin_bookmark, &bookmark_hash, &my_charset_bin, 32, 0, 0, get_bookmark_hash_key, NULL, HASH_UNIQUE)) goto err; @@ -1590,15 +1615,15 @@ int plugin_init(int *argc, char **argv, int flags) The 80 is from 2016-04-27 when we had 71 default plugins Big enough to avoid many mallocs even in future */ - if (my_init_dynamic_array(&plugin_dl_array, + if (my_init_dynamic_array(key_memory_mysql_plugin_dl, &plugin_dl_array, sizeof(struct st_plugin_dl *), 16, 16, MYF(0)) || - my_init_dynamic_array(&plugin_array, + my_init_dynamic_array(key_memory_mysql_plugin, &plugin_array, sizeof(struct st_plugin_int *), 80, 32, MYF(0))) goto err; for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++) { - if (my_hash_init(&plugin_hash[i], system_charset_info, 32, 0, 0, + if (my_hash_init(key_memory_plugin_mem_root, &plugin_hash[i], system_charset_info, 32, 0, 0, get_plugin_hash_key, NULL, HASH_UNIQUE)) goto err; } @@ -2214,6 +2239,7 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name, mysql_audit_acquire_plugins(thd, event_class_mask); mysql_mutex_lock(&LOCK_plugin); + DEBUG_SYNC(thd, "acquired_LOCK_plugin"); error= plugin_add(thd->mem_root, thd->lex->create_info.if_not_exists(), name, &dl, MYF(0)); if (unlikely(error != INSTALL_GOOD)) @@ -2832,7 +2858,8 @@ static void update_func_str(THD *thd, struct st_mysql_sys_var *var, { char *old= *(char**) tgt; if (value) - *(char**) tgt= my_strdup(value, MYF(0)); + *(char**) tgt= my_strdup(key_memory_global_system_variables, + value, MYF(0)); else *(char**) tgt= 0; my_free(old); @@ -2976,10 +3003,12 @@ static st_bookmark *register_var(const char *plugin, const char *name, if (new_size > global_variables_dynamic_size) { global_system_variables.dynamic_variables_ptr= (char*) - my_realloc(global_system_variables.dynamic_variables_ptr, new_size, + my_realloc(key_memory_global_system_variables, + global_system_variables.dynamic_variables_ptr, new_size, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); max_system_variables.dynamic_variables_ptr= (char*) - my_realloc(max_system_variables.dynamic_variables_ptr, new_size, + my_realloc(key_memory_global_system_variables, + max_system_variables.dynamic_variables_ptr, new_size, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); /* Clear the new variable value space. This is required for string @@ -3021,7 +3050,8 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock) uint idx; thd->variables.dynamic_variables_ptr= (char*) - my_realloc(thd->variables.dynamic_variables_ptr, + my_realloc(key_memory_THD_variables, + thd->variables.dynamic_variables_ptr, global_variables_dynamic_size, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); @@ -3055,7 +3085,7 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock) { char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset); if (*pp) - *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); + *pp= my_strdup(key_memory_THD_variables, *pp, MYF(MY_WME|MY_FAE)); } } @@ -3912,7 +3942,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, (opt->flags & PLUGIN_VAR_MEMALLOC)) { char *def_val= *(char**)var_def_ptr(opt); - *(char**)val= def_val ? my_strdup(def_val, MYF(0)) : NULL; + *(char**)val= def_val ? my_strdup(PSI_INSTRUMENT_ME, def_val, MYF(0)) : NULL; } else memcpy(val, var_def_ptr(opt), var_storage_size(opt->flags)); @@ -4349,9 +4379,7 @@ int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value) void plugin_mutex_init() { -#ifdef HAVE_PSI_INTERFACE init_plugin_psi_keys(); -#endif mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dcf445f3cfb..98ffc842196 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -99,7 +99,6 @@ When one supplies long data for a placeholder: #include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert #include "sql_update.h" // mysql_prepare_update #include "sql_db.h" // mysql_opt_change_db, mysql_change_db -#include "sql_acl.h" // *_ACL #include "sql_derived.h" // mysql_derived_prepare, // mysql_handle_derived #include "sql_cte.h" @@ -122,6 +121,7 @@ When one supplies long data for a placeholder: #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "sql_handler.h" #include "transaction.h" // trans_rollback_implicit +#include "mysql/psi/mysql_ps.h" // MYSQL_EXECUTE_PS #include "wsrep_mysqld.h" /** @@ -160,6 +160,7 @@ public: }; THD *thd; + PSI_prepared_stmt* m_prepared_stmt; Select_fetch_protocol_binary result; Item_param **param_array; Server_side_cursor *cursor; @@ -1947,7 +1948,7 @@ static int mysql_test_show_slave_status(Prepared_statement *stmt, /** - Validate and prepare for execution SHOW MASTER STATUS statement. + Validate and prepare for execution SHOW BINLOG STATUS statement. @param stmt prepared statement @@ -1957,9 +1958,9 @@ static int mysql_test_show_slave_status(Prepared_statement *stmt, TRUE error, error message is set in THD */ -static int mysql_test_show_master_status(Prepared_statement *stmt) +static int mysql_test_show_binlog_status(Prepared_statement *stmt) { - DBUG_ENTER("mysql_test_show_master_status"); + DBUG_ENTER("mysql_test_show_binlog_status"); THD *thd= stmt->thd; List<Item> fields; @@ -2408,8 +2409,8 @@ static bool check_prepared_statement(Prepared_statement *stmt) } break; } - case SQLCOM_SHOW_MASTER_STAT: - if ((res= mysql_test_show_master_status(stmt)) == 2) + case SQLCOM_SHOW_BINLOG_STAT: + if ((res= mysql_test_show_binlog_status(stmt)) == 2) { /* Statement and field info has already been sent */ DBUG_RETURN(FALSE); @@ -2664,6 +2665,11 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) thd->protocol= &thd->protocol_binary; + /* Create PS table entry, set query text after rewrite. */ + stmt->m_prepared_stmt= MYSQL_CREATE_PS(stmt, stmt->id, + thd->m_statement_psi, + stmt->name.str, stmt->name.length); + if (stmt->prepare(packet, packet_length)) { /* Statement map deletes statement on erase */ @@ -2865,6 +2871,11 @@ void mysql_sql_stmt_prepare(THD *thd) */ Item_change_list_savepoint change_list_savepoint(thd); + /* Create PS table entry, set query text after rewrite. */ + stmt->m_prepared_stmt= MYSQL_CREATE_PS(stmt, stmt->id, + thd->m_statement_psi, + stmt->name.str, stmt->name.length); + if (stmt->prepare(query.str, (uint) query.length)) { /* Statement map deletes the statement on erase */ @@ -3260,6 +3271,8 @@ static void mysql_stmt_execute_common(THD *thd, open_cursor= MY_TEST(cursor_flags & (ulong) CURSOR_TYPE_READ_ONLY); thd->protocol= &thd->protocol_binary; + MYSQL_EXECUTE_PS(thd->m_statement_psi, stmt->m_prepared_stmt); + if (!bulk_op) stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); else @@ -3369,6 +3382,8 @@ void mysql_sql_stmt_execute(THD *thd) CALL p1('x'); */ Item_change_list_savepoint change_list_savepoint(thd); + MYSQL_EXECUTE_PS(thd->m_statement_psi, stmt->m_prepared_stmt); + (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL); change_list_savepoint.rollback(thd); thd->free_items(); // Free items created by execute_loop() @@ -3787,6 +3802,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg) STMT_INITIALIZED, ((++thd_arg->statement_id_counter) & STMT_ID_MASK)), thd(thd_arg), + m_prepared_stmt(NULL), result(thd_arg), param_array(0), cursor(0), @@ -3800,10 +3816,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg) read_types(0), m_sql_mode(thd->variables.sql_mode) { - init_sql_alloc(&main_mem_root, "Prepared_statement", - thd_arg->variables.query_alloc_block_size, - thd_arg->variables.query_prealloc_size, - MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_prepared_statement_main_mem_root, + &main_mem_root, thd_arg->variables.query_alloc_block_size, + thd_arg->variables.query_prealloc_size, MYF(MY_THREAD_SPECIFIC)); *last_error= '\0'; } @@ -3869,6 +3884,9 @@ Prepared_statement::~Prepared_statement() DBUG_ENTER("Prepared_statement::~Prepared_statement"); DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor)); + + MYSQL_DESTROY_PS(m_prepared_stmt); + delete cursor; /* We have to call free on the items even if cleanup is called as some items, @@ -4102,6 +4120,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) state= Query_arena::STMT_PREPARED; flags&= ~ (uint) IS_IN_USE; + MYSQL_SET_PS_TEXT(m_prepared_stmt, query(), query_length()); + /* Log COM_EXECUTE to the general log. Note, that in case of SQL prepared statements this causes two records to be output: @@ -4519,6 +4539,7 @@ Prepared_statement::reprepare() if (likely(!error)) { + MYSQL_REPREPARE_PS(m_prepared_stmt); swap_prepared_statement(©); swap_parameter_array(param_array, copy.param_array, param_count); #ifdef DBUG_ASSERT_EXISTS @@ -4756,17 +4777,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) if (query_cache_send_result_to_client(thd, thd->query(), thd->query_length()) <= 0) { - PSI_statement_locker *parent_locker; MYSQL_QUERY_EXEC_START(thd->query(), thd->thread_id, thd->get_db(), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 1); - parent_locker= thd->m_statement_psi; - thd->m_statement_psi= NULL; error= mysql_execute_command(thd); - thd->m_statement_psi= parent_locker; MYSQL_QUERY_EXEC_DONE(error); } else @@ -4879,7 +4896,11 @@ bool Prepared_statement::execute_immediate(const char *query, uint query_len) set_sql_prepare(); name= execute_immediate_stmt_name; // for DBUG_PRINT etc - if (unlikely(prepare(query, query_len))) + + m_prepared_stmt= MYSQL_CREATE_PS(this, id, thd->m_statement_psi, + name.str, name.length); + + if (prepare(query, query_len)) DBUG_RETURN(true); if (param_count != thd->lex->prepared_stmt.param_count()) @@ -4889,6 +4910,7 @@ bool Prepared_statement::execute_immediate(const char *query, uint query_len) DBUG_RETURN(true); } + MYSQL_EXECUTE_PS(thd->m_statement_psi, m_prepared_stmt); (void) execute_loop(&expanded_query, FALSE, NULL, NULL); deallocate_immediate(); DBUG_RETURN(false); @@ -5388,8 +5410,8 @@ bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint) { DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root)); - init_sql_alloc(&m_rset_root, "send_result_set_metadata", - MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(PSI_INSTRUMENT_ME, &m_rset_root, MEM_ROOT_BLOCK_SIZE, 0, + MYF(MY_THREAD_SPECIFIC)); if (! (m_rset= new (&m_rset_root) List<Ed_row>)) return TRUE; diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index cee55761a98..2a47aa846eb 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -200,7 +200,8 @@ void PROF_MEASUREMENT::set_label(const char *status_arg, sizes[1]= (function_arg == NULL) ? 0 : strlen(function_arg) + 1; sizes[2]= (file_arg == NULL) ? 0 : strlen(file_arg) + 1; - allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); + allocated_status_memory= (char *) my_malloc(key_memory_PROFILE, sizes[0] + + sizes[1] + sizes[2], MYF(0)); DBUG_ASSERT(allocated_status_memory != NULL); cursor= allocated_status_memory; @@ -289,7 +290,7 @@ void QUERY_PROFILE::set_query_source(char *query_source_arg, size_t query_length DBUG_ASSERT(query_source == NULL); /* we don't leak memory */ if (query_source_arg != NULL) - query_source= my_strndup(query_source_arg, length, MYF(0)); + query_source= my_strndup(key_memory_PROFILE, query_source_arg, length, MYF(0)); } void QUERY_PROFILE::new_status(const char *status_arg, diff --git a/sql/sql_profile.h b/sql/sql_profile.h index b0b1642ee02..85018a2598b 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -54,6 +54,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #include <sys/resource.h> #endif +extern PSI_memory_key key_memory_queue_item; class PROF_MEASUREMENT; class QUERY_PROFILE; @@ -100,7 +101,8 @@ public: { struct queue_item *new_item; - new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0)); + new_item= (struct queue_item *) my_malloc(key_memory_queue_item, + sizeof(struct queue_item), MYF(0)); new_item->payload= payload; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5bfa29b72c4..f11b3a35a80 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -24,7 +24,6 @@ #include "rpl_mi.h" #include "rpl_rli.h" #include "sql_repl.h" -#include "sql_acl.h" // SUPER_ACL #include "log_event.h" #include "rpl_filter.h" #include <my_dir.h> @@ -1221,7 +1220,8 @@ check_slave_start_position(binlog_send_info *info, const char **errormsg, if (!delete_list) { if (!(delete_list= (slave_connection_state::entry **) - my_malloc(sizeof(*delete_list) * st->hash.records, MYF(MY_WME)))) + my_malloc(PSI_INSTRUMENT_ME, + sizeof(*delete_list) * st->hash.records, MYF(MY_WME)))) { *errormsg= "Out of memory while checking slave start position"; err= ER_OUT_OF_RESOURCES; @@ -1283,8 +1283,9 @@ gtid_find_binlog_file(slave_connection_state *state, char *out_name, const char *errormsg= NULL; char buf[FN_REFLEN]; - init_alloc_root(&memroot, "gtid_find_binlog_file", - 8192, 0, MYF(MY_THREAD_SPECIFIC)); + init_alloc_root(PSI_INSTRUMENT_ME, &memroot, + 10*(FN_REFLEN+sizeof(binlog_file_entry)), 0, + MYF(MY_THREAD_SPECIFIC)); if (!(list= get_binlog_list(&memroot))) { errormsg= "Out of memory while looking for GTID position in binlog"; @@ -3079,7 +3080,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) char relay_log_info_file_tmp[FN_REFLEN]; DBUG_ENTER("start_slave"); - if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) + if (check_global_access(thd, PRIV_STMT_START_SLAVE)) DBUG_RETURN(-1); create_logfile_name_with_suffix(master_info_file_tmp, @@ -3282,7 +3283,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) DBUG_ENTER("stop_slave"); DBUG_PRINT("enter",("Connection: %s", mi->connection_name.str)); - if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) + if (check_global_access(thd, PRIV_STMT_STOP_SLAVE)) DBUG_RETURN(-1); THD_STAGE_INFO(thd, stage_killing_slave); int thread_mask; @@ -4215,7 +4216,7 @@ void show_binlog_info_get_fields(THD *thd, List<Item> *field_list) /** - Execute a SHOW MASTER STATUS statement. + Execute a SHOW BINLOG STATUS statement. @param thd Pointer to THD object for the client thread executing the statement. @@ -4307,8 +4308,7 @@ bool show_binlogs(THD* thd) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - init_alloc_root(&mem_root, "binlog_file_list", 8192, 0, - MYF(MY_THREAD_SPECIFIC)); + init_alloc_root(PSI_INSTRUMENT_ME, &mem_root, 8192, 0, MYF(MY_THREAD_SPECIFIC)); retry: /* The current mutex handling here is to ensure we get the current log position diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 09a15aaf7df..e8fd275c55b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -43,7 +43,6 @@ #include "sql_base.h" // setup_wild, setup_fields, fill_record #include "sql_parse.h" // check_stack_overrun #include "sql_partition.h" // make_used_partitions_str -#include "sql_acl.h" // *_ACL #include "sql_test.h" // print_where, print_keyuse_array, // print_sjm, print_plan, TEST_join #include "records.h" // init_read_record, end_read_record @@ -6769,7 +6768,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, /* set a barrier for the array of SARGABLE_PARAM */ (*sargables)[0].field= 0; - if (my_init_dynamic_array2(keyuse, sizeof(KEYUSE), + if (my_init_dynamic_array2(thd->mem_root->m_psi_key, keyuse, sizeof(KEYUSE), thd->alloc(sizeof(KEYUSE) * 20), 20, 64, MYF(MY_THREAD_SPECIFIC))) DBUG_RETURN(TRUE); @@ -13495,8 +13494,7 @@ bool JOIN_TAB::preread_init() if ((!derived->get_unit()->executed || derived->is_recursive_with_table() || derived->get_unit()->uncacheable) && - mysql_handle_single_derived(join->thd->lex, - derived, DT_CREATE | DT_FILL)) + mysql_handle_single_derived(join->thd->lex, derived, DT_CREATE | DT_FILL)) return TRUE; if (!(derived->get_unit()->uncacheable & UNCACHEABLE_DEPENDENT) || @@ -13521,6 +13519,21 @@ bool JOIN_TAB::preread_init() } +bool JOIN_TAB::pfs_batch_update(JOIN *join) +{ + /* + Use PFS batch mode if + 1. tab is an inner-most table, or + 2. will read more than one row (not eq_ref or const access type) + 3. no subqueries + */ + + return join->join_tab + join->table_count - 1 == this && // 1 + type != JT_EQ_REF && type != JT_CONST && type != JT_SYSTEM && // 2 + (!select_cond || !select_cond->with_subquery()); // 3 +} + + /** Build a TABLE_REF structure for index lookup in the temporary table @@ -18023,14 +18036,27 @@ class Create_tmp_table: public Data_type_statistics ORDER *m_group; bool m_distinct; bool m_save_sum_fields; + bool m_with_cycle; ulonglong m_select_options; ha_rows m_rows_limit; - uint m_hidden_field_count; // Remove this eventually uint m_group_null_items; - uint m_null_count; - uint m_hidden_uneven_bit_length; - uint m_hidden_null_count; + + // counter for distinct/other fields + uint m_field_count[2]; + // counter for distinct/other fields which can be NULL + uint m_null_count[2]; + // counter for distinct/other blob fields + uint m_blobs_count[2]; + // counter for "tails" of bit fields which do not fit in a byte + uint m_uneven_bit[2]; + public: + enum counter {distinct, other}; + /* + shows which field we are processing: distinct/other (set in processing + cycles) + */ + counter current_counter; Create_tmp_table(const TMP_TABLE_PARAM *param, ORDER *group, bool distinct, bool save_sum_fields, ulonglong select_options, ha_rows rows_limit) @@ -18040,14 +18066,21 @@ public: m_group(group), m_distinct(distinct), m_save_sum_fields(save_sum_fields), + m_with_cycle(false), m_select_options(select_options), m_rows_limit(rows_limit), - m_hidden_field_count(param->hidden_field_count), m_group_null_items(0), - m_null_count(0), - m_hidden_uneven_bit_length(0), - m_hidden_null_count(0) - { } + current_counter(other) + { + m_field_count[Create_tmp_table::distinct]= 0; + m_field_count[Create_tmp_table::other]= 0; + m_null_count[Create_tmp_table::distinct]= 0; + m_null_count[Create_tmp_table::other]= 0; + m_blobs_count[Create_tmp_table::distinct]= 0; + m_blobs_count[Create_tmp_table::other]= 0; + m_uneven_bit[Create_tmp_table::distinct]= 0; + m_uneven_bit[Create_tmp_table::other]= 0; + } void add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols); @@ -18080,13 +18113,16 @@ void Create_tmp_table::add_field(TABLE *table, Field *field, uint fieldnr, bool } if (!(field->flags & NOT_NULL_FLAG)) - m_null_count++; + m_null_count[current_counter]++; table->s->reclength+= field->pack_length(); // Assign it here, before update_data_type_statistics() changes m_blob_count if (field->flags & BLOB_FLAG) + { table->s->blob_field[m_blob_count]= fieldnr; + m_blobs_count[current_counter]++; + } table->field[fieldnr]= field; field->field_index= fieldnr; @@ -18215,7 +18251,7 @@ TABLE *Create_tmp_table::start(THD *thd, if (param->precomputed_group_by) copy_func_count+= param->sum_func_count; - init_sql_alloc(&own_root, "tmp_table", TABLE_ALLOC_BLOCK_SIZE, 0, + init_sql_alloc(key_memory_TABLE, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); if (!multi_alloc_root(&own_root, @@ -18298,6 +18334,7 @@ bool Create_tmp_table::add_fields(THD *thd, DBUG_ASSERT(table->s->blob_fields == 0); const bool not_all_columns= !(m_select_options & TMP_TABLE_ALL_COLUMNS); + bool distinct_record_structure= m_distinct; uint fieldnr= 0; TABLE_SHARE *share= table->s; Item **copy_func= param->items_to_copy; @@ -18308,8 +18345,29 @@ bool Create_tmp_table::add_fields(THD *thd, List_iterator_fast<Item> li(fields); Item *item; Field **tmp_from_field= m_from_field; + uint uneven_delta; + while (!m_with_cycle && (item= li++)) + if (item->common_flags & IS_IN_WITH_CYCLE) + { + m_with_cycle= true; + /* + Following distinct_record_structure is (m_distinct || m_with_cycle) + + Note: distinct_record_structure can be true even if m_distinct is + false, for example for incr_table in recursive CTE + (see select_union_recursive::create_result_table) + */ + distinct_record_structure= true; + } + li.rewind(); while ((item=li++)) { + current_counter= (((param->hidden_field_count < (fieldnr + 1)) && + distinct_record_structure && + (!m_with_cycle || + (item->common_flags & IS_IN_WITH_CYCLE)))? + distinct : + other); Item::Type type= item->type(); if (type == Item::COPY_STR_ITEM) { @@ -18334,7 +18392,8 @@ bool Create_tmp_table::add_fields(THD *thd, continue; } } - if (item->const_item() && (int) m_hidden_field_count <= 0) + if (item->const_item() && + param->hidden_field_count < (fieldnr + 1)) continue; // We don't have to store this } if (type == Item::SUM_FUNC_ITEM && !m_group && !m_save_sum_fields) @@ -18351,7 +18410,7 @@ bool Create_tmp_table::add_fields(THD *thd, create_tmp_field(table, arg, ©_func, tmp_from_field, &m_default_field[fieldnr], m_group != 0, not_all_columns, - m_distinct, false); + distinct_record_structure , false); if (!new_field) goto err; // Should be OOM tmp_from_field++; @@ -18363,7 +18422,10 @@ bool Create_tmp_table::add_fields(THD *thd, arg= sum_item->set_arg(i, thd, tmp_item); thd->mem_root= &table->mem_root; + uneven_delta= m_uneven_bit_length; add_field(table, new_field, fieldnr++, param->force_not_null_cols); + uneven_delta= m_uneven_bit_length - uneven_delta; + m_field_count[current_counter]++; if (!(new_field->flags & NOT_NULL_FLAG)) { @@ -18373,6 +18435,8 @@ bool Create_tmp_table::add_fields(THD *thd, */ arg->maybe_null=1; } + if (current_counter == distinct) + new_field->flags|= FIELD_PART_OF_TMP_UNIQUE; } } } @@ -18440,36 +18504,23 @@ bool Create_tmp_table::add_fields(THD *thd, } tmp_from_field++; + uneven_delta= m_uneven_bit_length; add_field(table, new_field, fieldnr++, param->force_not_null_cols); + uneven_delta= m_uneven_bit_length - uneven_delta; + m_field_count[current_counter]++; if (item->marker == 4 && item->maybe_null) { m_group_null_items++; new_field->flags|= GROUP_FLAG; } + if (current_counter == distinct) + new_field->flags|= FIELD_PART_OF_TMP_UNIQUE; } - if (!--m_hidden_field_count) - { - /* - This was the last hidden field; Remember how many hidden fields could - have null - */ - m_hidden_null_count= m_null_count; - /* - We need to update hidden_field_count as we may have stored group - functions with constant arguments - */ - param->hidden_field_count= fieldnr; - m_null_count= 0; - /* - On last hidden field we store uneven bit length in - m_hidden_uneven_bit_length and proceed calculation of - uneven bits for visible fields into m_uneven_bit_length. - */ - m_hidden_uneven_bit_length= m_uneven_bit_length; - m_uneven_bit_length= 0; - } + m_uneven_bit[current_counter]+= uneven_delta; } + DBUG_ASSERT(fieldnr == m_field_count[other] + m_field_count[distinct]); + DBUG_ASSERT(m_blob_count == m_blobs_count[other] + m_blobs_count[distinct]); share->fields= fieldnr; share->blob_fields= m_blob_count; table->field[fieldnr]= 0; // End marker @@ -18495,8 +18546,12 @@ bool Create_tmp_table::finalize(THD *thd, DBUG_ENTER("Create_tmp_table::finalize"); DBUG_ASSERT(table); - uint hidden_null_pack_length; - uint null_pack_length; + uint null_pack_length[2]; + uint null_pack_base[2]; + uint null_counter[2]= {0, 0}; + + uint whole_null_pack_length; + bool use_packed_rows= false; uchar *pos; uchar *null_flags; @@ -18547,16 +18602,21 @@ bool Create_tmp_table::finalize(THD *thd, if (share->blob_fields == 0) { /* We need to ensure that first byte is not 0 for the delete link */ - if (param->hidden_field_count) - m_hidden_null_count++; + if (m_field_count[other]) + m_null_count[other]++; else - m_null_count++; - } - hidden_null_pack_length= (m_hidden_null_count + 7 + - m_hidden_uneven_bit_length) / 8; - null_pack_length= (hidden_null_pack_length + - (m_null_count + m_uneven_bit_length + 7) / 8); - share->reclength+= null_pack_length; + m_null_count[distinct]++; + } + + null_pack_length[other]= (m_null_count[other] + 7 + + m_uneven_bit[other]) / 8; + null_pack_base[other]= 0; + null_pack_length[distinct]= (m_null_count[distinct] + 7 + + m_uneven_bit[distinct]) / 8; + null_pack_base[distinct]= null_pack_length[other]; + whole_null_pack_length= null_pack_length[other] + + null_pack_length[distinct]; + share->reclength+= whole_null_pack_length; if (!share->reclength) share->reclength= 1; // Dummy select /* Use packed rows if there is blobs or a lot of space to gain */ @@ -18580,43 +18640,53 @@ bool Create_tmp_table::finalize(THD *thd, recinfo=param->start_recinfo; null_flags=(uchar*) table->record[0]; - pos=table->record[0]+ null_pack_length; - if (null_pack_length) + pos=table->record[0]+ whole_null_pack_length; + if (whole_null_pack_length) { bzero((uchar*) recinfo,sizeof(*recinfo)); recinfo->type=FIELD_NORMAL; - recinfo->length=null_pack_length; + recinfo->length= whole_null_pack_length; recinfo++; - bfill(null_flags,null_pack_length,255); // Set null fields + bfill(null_flags, whole_null_pack_length, 255); // Set null fields table->null_flags= (uchar*) table->record[0]; - share->null_fields= m_null_count + m_hidden_null_count; - share->null_bytes= share->null_bytes_for_compare= null_pack_length; + share->null_fields= m_null_count[other] + m_null_count[distinct]; + share->null_bytes= share->null_bytes_for_compare= whole_null_pack_length; + } + + if (share->blob_fields == 0) + { + null_counter[(m_field_count[other] ? other : distinct)]++; } - m_null_count= (share->blob_fields == 0) ? 1 : 0; - m_hidden_field_count= param->hidden_field_count; for (uint i= 0; i < share->fields; i++, recinfo++) { Field *field= table->field[i]; uint length; bzero((uchar*) recinfo,sizeof(*recinfo)); + current_counter= ((field->flags & FIELD_PART_OF_TMP_UNIQUE) ? + distinct : + other); + if (!(field->flags & NOT_NULL_FLAG)) { - recinfo->null_bit= (uint8)1 << (m_null_count & 7); - recinfo->null_pos= m_null_count/8; - field->move_field(pos, null_flags + m_null_count/8, - (uint8)1 << (m_null_count & 7)); - m_null_count++; + + recinfo->null_bit= (uint8)1 << (null_counter[current_counter] & 7); + recinfo->null_pos= (null_pack_base[current_counter] + + null_counter[current_counter]/8); + field->move_field(pos, null_flags + recinfo->null_pos, recinfo->null_bit); + null_counter[current_counter]++; } else field->move_field(pos,(uchar*) 0,0); if (field->type() == MYSQL_TYPE_BIT) { /* We have to reserve place for extra bits among null bits */ - ((Field_bit*) field)->set_bit_ptr(null_flags + m_null_count / 8, - m_null_count & 7); - m_null_count+= (field->field_length & 7); + ((Field_bit*) field)->set_bit_ptr(null_flags + + null_pack_base[current_counter] + + null_counter[current_counter]/8, + null_counter[current_counter] & 7); + null_counter[current_counter]+= (field->field_length & 7); } field->reset(); @@ -18655,8 +18725,6 @@ bool Create_tmp_table::finalize(THD *thd, /* Make entry for create table */ recinfo->length=length; recinfo->type= field->tmp_engine_column_type(use_packed_rows); - if (!--m_hidden_field_count) - m_null_count= (m_null_count + 7) & ~7; // move to next byte // fix table name in field entry field->set_table_name(&table->alias); @@ -18777,7 +18845,8 @@ bool Create_tmp_table::finalize(THD *thd, m_group_buff <= param->group_buff + param->group_length); } - if (m_distinct && share->fields != param->hidden_field_count) + if (m_distinct && (share->fields != param->hidden_field_count || + m_with_cycle)) { uint i; Field **reg_field; @@ -18789,7 +18858,7 @@ bool Create_tmp_table::finalize(THD *thd, */ DBUG_PRINT("info",("hidden_field_count: %d", param->hidden_field_count)); - if (share->blob_fields) + if (m_blobs_count[distinct]) { /* Special mode for index creation in MyISAM used to support unique @@ -18798,10 +18867,8 @@ bool Create_tmp_table::finalize(THD *thd, */ share->uniques= 1; } - null_pack_length-=hidden_null_pack_length; - keyinfo->user_defined_key_parts= - ((share->fields - param->hidden_field_count)+ - (share->uniques ? MY_TEST(null_pack_length) : 0)); + keyinfo->user_defined_key_parts= m_field_count[distinct] + + (share->uniques ? MY_TEST(null_pack_length[distinct]) : 0); keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->usable_key_parts= keyinfo->user_defined_key_parts; table->distinct= 1; @@ -18844,11 +18911,11 @@ bool Create_tmp_table::finalize(THD *thd, blobs can distinguish NULL from 0. This extra field is not needed when we do not use UNIQUE indexes for blobs. */ - if (null_pack_length && share->uniques) + if (null_pack_length[distinct] && share->uniques) { m_key_part_info->null_bit=0; - m_key_part_info->offset=hidden_null_pack_length; - m_key_part_info->length=null_pack_length; + m_key_part_info->offset= null_pack_base[distinct]; + m_key_part_info->length= null_pack_length[distinct]; m_key_part_info->field= new Field_string(table->record[0], (uint32) m_key_part_info->length, (uchar*) 0, @@ -18866,8 +18933,10 @@ bool Create_tmp_table::finalize(THD *thd, /* Create a distinct key over the columns we are going to return */ for (i= param->hidden_field_count, reg_field= table->field + i ; i < share->fields; - i++, reg_field++, m_key_part_info++) + i++, reg_field++) { + if (!((*reg_field)->flags & FIELD_PART_OF_TMP_UNIQUE)) + continue; m_key_part_info->field= *reg_field; (*reg_field)->flags |= PART_KEY_FLAG; if (m_key_part_info == keyinfo->key_part) @@ -18904,6 +18973,8 @@ bool Create_tmp_table::finalize(THD *thd, (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT1 || (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT2) ? 0 : FIELDFLAG_BINARY; + + m_key_part_info++; } } @@ -20446,6 +20517,10 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) if (join_tab->loosescan_match_tab) join_tab->loosescan_match_tab->found_match= FALSE; + const bool pfs_batch_update= join_tab->pfs_batch_update(join); + if (pfs_batch_update) + join_tab->table->file->start_psi_batch_mode(); + if (rc != NESTED_LOOP_NO_MORE_ROWS) { error= (*join_tab->read_first_record)(join_tab); @@ -20497,6 +20572,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) join_tab->last_inner && !join_tab->found) rc= evaluate_null_complemented_join_record(join, join_tab); + if (pfs_batch_update) + join_tab->table->file->end_psi_batch_mode(); + if (rc == NESTED_LOOP_NO_MORE_ROWS) rc= NESTED_LOOP_OK; DBUG_RETURN(rc); @@ -23952,21 +24030,21 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, Field **ptr; DBUG_ENTER("remove_dup_with_hash_index"); - if (unlikely(!my_multi_malloc(MYF(MY_WME), - &key_buffer, - (uint) ((key_length + extra_length) * - (long) file->stats.records), - &field_lengths, - (uint) (field_count*sizeof(*field_lengths)), - NullS))) + if (!my_multi_malloc(key_memory_hash_index_key_buffer, MYF(MY_WME), + &key_buffer, + (uint) ((key_length + extra_length) * + (long) file->stats.records), + &field_lengths, + (uint) (field_count*sizeof(*field_lengths)), + NullS)) DBUG_RETURN(1); for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++) (*field_length++)= (*ptr)->sort_length(); - if (unlikely(my_hash_init(&hash, &my_charset_bin, - (uint) file->stats.records, 0, - key_length, (my_hash_get_key) 0, 0, 0))) + if (my_hash_init(key_memory_hash_index_key_buffer, &hash, &my_charset_bin, + (uint) file->stats.records, 0, key_length, + (my_hash_get_key) 0, 0, 0)) { my_free(key_buffer); DBUG_RETURN(1); @@ -24002,7 +24080,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, field_length=field_lengths; for (ptr= first_field ; *ptr ; ptr++) { - (*ptr)->make_sort_key(key_pos, *field_length); + (*ptr)->make_sort_key_part(key_pos, *field_length); key_pos+= (*ptr)->maybe_null() + *field_length++; } /* Check if it exists before */ @@ -27481,7 +27559,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) else str->append(','); - if (is_subquery_function() && item->is_autogenerated_name) + if (is_subquery_function() && item->is_autogenerated_name()) { /* Do not print auto-generated aliases in subqueries. It has no purpose @@ -27777,8 +27855,8 @@ JOIN::reoptimize(Item *added_where, table_map join_tables, reset_query_plan(); if (!keyuse.buffer && - my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64, - MYF(MY_THREAD_SPECIFIC))) + my_init_dynamic_array(thd->mem_root->m_psi_key, &keyuse, sizeof(KEYUSE), + 20, 64, MYF(MY_THREAD_SPECIFIC))) { delete_dynamic(&added_keyuse); return REOPT_ERROR; diff --git a/sql/sql_select.h b/sql/sql_select.h index e3501fb98c6..8b2df74702b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -247,13 +247,13 @@ class SplM_opt_info; typedef struct st_join_table { TABLE *table; TABLE_LIST *tab_list; - KEYUSE *keyuse; /**< pointer to first used key */ + KEYUSE *keyuse; /**< pointer to first used key */ KEY *hj_key; /**< descriptor of the used best hash join key - not supported by any index */ + not supported by any index */ SQL_SELECT *select; COND *select_cond; COND *on_precond; /**< part of on condition to check before - accessing the first inner table */ + accessing the first inner table */ QUICK_SELECT_I *quick; /* The value of select_cond before we've attempted to do Index Condition @@ -635,6 +635,8 @@ typedef struct st_join_table { ha_rows get_examined_rows(); bool preread_init(); + bool pfs_batch_update(JOIN *join); + bool is_sjm_nest() { return MY_TEST(bush_children); } /* @@ -1095,7 +1097,7 @@ protected: keyuse.buffer= NULL; keyuse.malloc_flags= 0; best_positions= 0; /* To detect errors */ - error= my_multi_malloc(MYF(MY_WME), + error= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &best_positions, sizeof(*best_positions) * (tables + 1), &join_tab_keyuse, diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 8b2f49a5910..a5676b8989a 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -452,10 +452,9 @@ int SEQUENCE::read_initial_values(TABLE *table) where we don't have a mdl lock on the table */ - mdl_request.init(MDL_key::TABLE, - table->s->db.str, - table->s->table_name.str, - MDL_SHARED_READ, MDL_EXPLICIT); + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, table->s->db.str, + table->s->table_name.str, MDL_SHARED_READ, + MDL_EXPLICIT); mdl_requests.push_front(&mdl_request); if (thd->mdl_context.acquire_locks(&mdl_requests, thd->variables.lock_wait_timeout)) diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 7913a7d2b9f..1d12e95bbbb 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -93,6 +93,8 @@ static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length, DBUG_RETURN((uchar*) server->server_name); } +static PSI_memory_key key_memory_servers; + #ifdef HAVE_PSI_INTERFACE static PSI_rwlock_key key_rwlock_THR_LOCK_servers; @@ -101,6 +103,11 @@ static PSI_rwlock_info all_servers_cache_rwlocks[]= { &key_rwlock_THR_LOCK_servers, "THR_LOCK_servers", PSI_FLAG_GLOBAL} }; +static PSI_memory_info all_servers_cache_memory[]= +{ + { &key_memory_servers, "servers_cache", PSI_FLAG_GLOBAL} +}; + static void init_servers_cache_psi_keys(void) { const char* category= "sql"; @@ -111,6 +118,9 @@ static void init_servers_cache_psi_keys(void) count= array_elements(all_servers_cache_rwlocks); PSI_server->register_rwlock(category, all_servers_cache_rwlocks, count); + + count= array_elements(all_servers_cache_memory); + mysql_memory_register(category, all_servers_cache_memory, count); } #endif /* HAVE_PSI_INTERFACE */ @@ -148,7 +158,7 @@ bool servers_init(bool dont_read_servers_table) DBUG_RETURN(TRUE); /* initialise our servers cache */ - if (my_hash_init(&servers_cache, system_charset_info, 32, 0, 0, + if (my_hash_init(key_memory_servers, &servers_cache, system_charset_info, 32, 0, 0, (my_hash_get_key) servers_cache_get_key, 0, 0)) { return_val= TRUE; /* we failed, out of memory? */ @@ -156,7 +166,7 @@ bool servers_init(bool dont_read_servers_table) } /* Initialize the mem root for data */ - init_sql_alloc(&mem, "servers", ACL_ALLOC_BLOCK_SIZE, 0, + init_sql_alloc(key_memory_servers, &mem, ACL_ALLOC_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); if (dont_read_servers_table) @@ -206,7 +216,7 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) my_hash_reset(&servers_cache); free_root(&mem, MYF(0)); - init_sql_alloc(&mem, "servers_load", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_servers, &mem, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); if (init_read_record(&read_record_info,thd,table=tables[0].table, NULL, NULL, 1,0, FALSE)) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 94a28e74eff..02f6278140c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -480,7 +480,10 @@ static struct show_privileges_st sys_privileges[]= {"Proxy", "Server Admin", "To make proxy user possible"}, {"References", "Databases,Tables", "To have references on tables"}, {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"}, - {"Replication client","Server Admin","To ask where the slave or master servers are"}, + {"Binlog admin", "Server", "To purge binary logs"}, + {"Binlog monitor", "Server", "To use SHOW BINLOG STATUS and SHOW BINARY LOG"}, + {"Replication master admin", "Server", "To monitor connected slaves"}, + {"Replication slave admin", "Server", "To start/monitor/stop slave and apply binlog events"}, {"Replication slave","Server Admin","To read binary log events from the master"}, {"Select", "Tables", "To retrieve rows from table"}, {"Show databases","Server Admin","To see all databases with SHOW DATABASES"}, @@ -490,6 +493,10 @@ static struct show_privileges_st sys_privileges[]= {"Trigger","Tables", "To use triggers"}, {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"}, {"Update", "Tables", "To update existing rows"}, + {"Set user","Server", "To create views and stored routines with a different definer"}, + {"Federated admin", "Server", "To execute the CREATE SERVER, ALTER SERVER, DROP SERVER statements"}, + {"Connection admin", "Server", "To bypass connection limits and kill other users' connections"}, + {"Read_only admin", "Server", "To perform write operations even if @@read_only=ON"}, {"Usage","Server Admin","No privileges - allow connect only"}, {NullS, NullS, NullS} }; @@ -571,8 +578,8 @@ static bool skip_ignored_dir_check= TRUE; bool ignore_db_dirs_init() { - return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_CSTRING *), - 0, 0, MYF(0)); + return my_init_dynamic_array(key_memory_ignored_db, &ignore_db_dirs_array, + sizeof(LEX_STRING *), 0, 0, MYF(0)); } @@ -620,8 +627,8 @@ push_ignored_db_dir(char *path) return true; // No need to normalize, it's only a directory name, not a path. - if (!my_multi_malloc(0, - &new_elt, sizeof(LEX_CSTRING), + if (!my_multi_malloc(key_memory_ignored_db, MYF(0), + &new_elt, sizeof(LEX_STRING), &new_elt_buffer, path_len + 1, NullS)) return true; @@ -701,7 +708,7 @@ void ignore_db_dirs_append(const char *dirname_arg) LEX_STRING *new_entry; size_t len= strlen(dirname_arg); - if (!my_multi_malloc(0, + if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(0), &new_entry, sizeof(LEX_STRING), &new_entry_buf, len + 1, NullS)) @@ -723,7 +730,7 @@ void ignore_db_dirs_append(const char *dirname_arg) // Add one for comma and one for \0. size_t newlen= curlen + len + 1 + 1; char *new_db_dirs; - if (!(new_db_dirs= (char*)my_malloc(newlen ,MYF(0)))) + if (!(new_db_dirs= (char*)my_malloc(PSI_INSTRUMENT_ME, newlen, MYF(0)))) { // This is not a critical condition return; @@ -749,12 +756,10 @@ ignore_db_dirs_process_additions() skip_ignored_dir_check= TRUE; - if (my_hash_init(&ignore_db_dirs_hash, - lower_case_table_names ? - character_set_filesystem : &my_charset_bin, - 0, 0, 0, db_dirs_hash_get_key, - dispose_db_dir, - HASH_UNIQUE)) + if (my_hash_init(key_memory_ignored_db, &ignore_db_dirs_hash, + lower_case_table_names ? character_set_filesystem : + &my_charset_bin, 0, 0, 0, db_dirs_hash_get_key, + dispose_db_dir, HASH_UNIQUE)) return true; /* len starts from 1 because of the terminating zero. */ @@ -776,7 +781,8 @@ ignore_db_dirs_process_additions() len--; /* +1 the terminating zero */ - ptr= opt_ignore_db_dirs= (char *) my_malloc(len + 1, MYF(0)); + ptr= opt_ignore_db_dirs= (char *) my_malloc(key_memory_ignored_db, len + 1, + MYF(0)); if (!ptr) return true; @@ -1976,6 +1982,14 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start, packet->append(STRING_WITH_LEN(")")); } +int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, + Table_specification_st *create_info_arg, + enum_with_db_name with_db_name) +{ + return show_create_table_ex(thd, table_list, NULL, NULL, packet, + create_info_arg, with_db_name); +} + /* Build a CREATE TABLE statement for a table. @@ -1984,6 +1998,11 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start, thd The thread table_list A list containing one table to write statement for. + force_db If not NULL, database name to use in the CREATE + TABLE statement. + force_name If not NULL, table name to use in the CREATE TABLE + statement. if NULL, the name from table_list will be + used. packet Pointer to a string where statement will be written. create_info_arg Pointer to create information that can be used @@ -2000,9 +2019,11 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start, 0 OK */ -int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, - Table_specification_st *create_info_arg, - enum_with_db_name with_db_name) +int show_create_table_ex(THD *thd, TABLE_LIST *table_list, + const char *force_db, const char *force_name, + String *packet, + Table_specification_st *create_info_arg, + enum_with_db_name with_db_name) { List<Item> field_list; char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH]; @@ -2052,41 +2073,55 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN("TABLE ")); if (create_info_arg && create_info_arg->if_not_exists()) packet->append(STRING_WITH_LEN("IF NOT EXISTS ")); - if (table_list->schema_table) + + if (force_name) { - alias.str= table_list->schema_table->table_name; - alias.length= strlen(alias.str); + if (force_db) + { + append_identifier(thd, packet, force_db, strlen(force_db)); + packet->append(STRING_WITH_LEN(".")); + } + append_identifier(thd, packet, force_name, strlen(force_name)); } else { - if (lower_case_table_names == 2) + if (table_list->schema_table) { - alias.str= table->alias.c_ptr(); - alias.length= table->alias.length(); + alias.str= table_list->schema_table->table_name; + alias.length= strlen(alias.str); } else - alias= share->table_name; - } + { + if (lower_case_table_names == 2) + { + alias.str= table->alias.c_ptr(); + alias.length= table->alias.length(); + } + else + alias= share->table_name; + } - /* - Print the database before the table name if told to do that. The - database name is only printed in the event that it is different - from the current database. The main reason for doing this is to - avoid having to update gazillions of tests and result files, but - it also saves a few bytes of the binary log. - */ - if (with_db_name == WITH_DB_NAME) - { - const LEX_CSTRING *const db= - table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db; - if (!thd->db.str || cmp(db, &thd->db)) - { - append_identifier(thd, packet, db); - packet->append(STRING_WITH_LEN(".")); + /* + Print the database before the table name if told to do that. The + database name is only printed in the event that it is different + from the current database. The main reason for doing this is to + avoid having to update gazillions of tests and result files, but + it also saves a few bytes of the binary log. + */ + if (with_db_name == WITH_DB_NAME) + { + const LEX_CSTRING *const db= + table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db; + if (!thd->db.str || cmp(db, &thd->db)) + { + append_identifier(thd, packet, db); + packet->append(STRING_WITH_LEN(".")); + } } + + append_identifier(thd, packet, &alias); } - append_identifier(thd, packet, &alias); packet->append(STRING_WITH_LEN(" (\n")); /* We need this to get default values from the table @@ -3025,8 +3060,8 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond) DBUG_ASSERT(cond==NULL); thread_id= thd->lex->value_list.head()->val_int(); - calling_user= (thd->security_ctx->master_access & PROCESS_ACL) ? NullS : - thd->security_ctx->priv_user; + calling_user= (thd->security_ctx->master_access & PRIV_STMT_SHOW_EXPLAIN) ? + NullS : thd->security_ctx->priv_user; if ((tmp= find_thread_by_id(thread_id))) { @@ -3143,8 +3178,9 @@ static my_bool processlist_callback(THD *tmp, processlist_callback_arg *arg) const char *val; ulonglong max_counter; bool got_thd_data; - char *user= arg->thd->security_ctx->master_access & PROCESS_ACL ? - NullS : arg->thd->security_ctx->priv_user; + char *user= + arg->thd->security_ctx->master_access & PRIV_STMT_SHOW_PROCESSLIST ? + NullS : arg->thd->security_ctx->priv_user; if ((!tmp->vio_ok() && !tmp->system_thread) || (user && (tmp->system_thread || !tmp_sctx->user || @@ -3277,8 +3313,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) Status functions *****************************************************************************/ -static DYNAMIC_ARRAY all_status_vars; +DYNAMIC_ARRAY all_status_vars; static bool status_vars_inited= 0; +ulonglong status_var_array_version= 0; C_MODE_START static int show_var_cmp(const void *var1, const void *var2) @@ -3306,6 +3343,7 @@ static void shrink_var_array(DYNAMIC_ARRAY *array) } else // array is completely empty - delete it delete_dynamic(array); + status_var_array_version++; } /* @@ -3333,7 +3371,8 @@ int add_status_vars(SHOW_VAR *list) if (status_vars_inited) mysql_rwlock_wrlock(&LOCK_all_status_vars); if (!all_status_vars.buffer && // array is not allocated yet - do it now - my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 250, 50, MYF(0))) + my_init_dynamic_array(PSI_INSTRUMENT_ME, &all_status_vars, + sizeof(SHOW_VAR), 250, 50, MYF(0))) { res= 1; goto err; @@ -3344,6 +3383,7 @@ int add_status_vars(SHOW_VAR *list) all_status_vars.elements--; // but next insert_dynamic should overwite it if (status_vars_inited) sort_dynamic(&all_status_vars, show_var_cmp); + status_var_array_version++; err: if (status_vars_inited) mysql_rwlock_unlock(&LOCK_all_status_vars); @@ -3362,6 +3402,7 @@ void init_status_vars() { status_vars_inited=1; sort_dynamic(&all_status_vars, show_var_cmp); + status_var_array_version++; } void reset_status_vars() @@ -3388,6 +3429,7 @@ void reset_status_vars() void free_status_vars() { delete_dynamic(&all_status_vars); + status_var_array_version++; } /* @@ -3449,6 +3491,11 @@ void remove_status_vars(SHOW_VAR *list) } } +/* Current version of the all_status_vars. */ +ulonglong get_status_vars_version(void) +{ + return status_var_array_version; +} /** @brief Returns the value of a system or a status variable. @@ -4738,8 +4785,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table, bool can_deadlock) { bool error; - table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str, - MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION); + MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str, + table->table_name.str, MDL_SHARED_HIGH_PRIO, + MDL_TRANSACTION); if (can_deadlock) { @@ -4861,8 +4909,8 @@ static int fill_schema_table_from_frm(THD *thd, TABLE *table, if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY) { - init_sql_alloc(&tbl.mem_root, "fill_schema_table_from_frm", - TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_table_triggers_list, + &tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); if (!Table_triggers_list::check_n_load(thd, db_name, table_name, &tbl, 1)) { @@ -5016,7 +5064,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) ST_SCHEMA_TABLE *schema_table= tables->schema_table; IS_table_read_plan *plan= tables->is_table_read_plan; enum enum_schema_tables schema_table_idx; - Dynamic_array<LEX_CSTRING*> db_names; + Dynamic_array<LEX_CSTRING*> db_names(PSI_INSTRUMENT_MEM); Item *partial_cond= plan->partial_cond; int error= 1; Open_tables_backup open_tables_state_backup; @@ -5085,7 +5133,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) goto err; /* Use tmp_mem_root to allocate data for opened tables */ - init_alloc_root(&tmp_mem_root, "get_all_tables", SHOW_ALLOC_BLOCK_SIZE, + init_alloc_root(PSI_INSTRUMENT_ME, &tmp_mem_root, SHOW_ALLOC_BLOCK_SIZE, SHOW_ALLOC_BLOCK_SIZE, MY_THREAD_SPECIFIC); for (size_t i=0; i < db_names.elements(); i++) @@ -5100,7 +5148,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) #endif { - Dynamic_array<LEX_CSTRING*> table_names; + Dynamic_array<LEX_CSTRING*> table_names(PSI_INSTRUMENT_MEM); int res= make_table_name_list(thd, &table_names, lex, &plan->lookup_field_vals, db_name); if (unlikely(res == 2)) /* Not fatal error, continue */ @@ -5216,7 +5264,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) */ LOOKUP_FIELD_VALUES lookup_field_vals; - Dynamic_array<LEX_CSTRING*> db_names; + Dynamic_array<LEX_CSTRING*> db_names(PSI_INSTRUMENT_MEM); Schema_specification_st create; TABLE *table= tables->table; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -6200,11 +6248,11 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, 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); sql_mode= (sql_mode_t) proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(); - sph= Sp_handler::handler_mysql_proc((stored_procedure_type) + sph= Sp_handler::handler_mysql_proc((enum_sp_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]-> val_int()); - if (!sph || sph->type() == TYPE_ENUM_PACKAGE || - sph->type() == TYPE_ENUM_PACKAGE_BODY) + if (!sph || sph->type() == SP_TYPE_PACKAGE || + sph->type() == SP_TYPE_PACKAGE_BODY) DBUG_RETURN(0); if (!full_access) @@ -6215,7 +6263,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root, ¶ms); - if (sph->type() == TYPE_ENUM_FUNCTION) + if (sph->type() == SP_TYPE_FUNCTION) proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root, &returns); sp= sph->sp_load_for_information_schema(thd, proc_table, db, name, @@ -6228,7 +6276,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, Sql_mode_save sql_mode_backup(thd); thd->variables.sql_mode= sql_mode; - if (sph->type() == TYPE_ENUM_FUNCTION) + if (sph->type() == SP_TYPE_FUNCTION) { restore_record(table, s->default_values); table->field[0]->store(STRING_WITH_LEN("def"), cs); @@ -6312,7 +6360,7 @@ bool store_schema_proc(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_NAME]->val_str_nopad(thd->mem_root, &name); proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer); - sph= Sp_handler::handler_mysql_proc((stored_procedure_type) + sph= Sp_handler::handler_mysql_proc((enum_sp_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]-> val_int()); if (!sph) @@ -6341,7 +6389,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, copy_field_as_string(table->field[4], proc_table->field[MYSQL_PROC_MYSQL_TYPE]); - if (sph->type() == TYPE_ENUM_FUNCTION) + if (sph->type() == SP_TYPE_FUNCTION) { sp_head *sp; bool free_sp_head; @@ -9504,7 +9552,8 @@ int initialize_schema_table(st_plugin_int *plugin) ST_SCHEMA_TABLE *schema_table; DBUG_ENTER("initialize_schema_table"); - if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE), + if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(key_memory_ST_SCHEMA_TABLE, + sizeof(ST_SCHEMA_TABLE), MYF(MY_WME | MY_ZEROFILL)))) DBUG_RETURN(1); /* Historical Requirement */ diff --git a/sql/sql_show.h b/sql/sql_show.h index a98ba451088..80588cda8b5 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -83,6 +83,12 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, Table_specification_st *create_info_arg, enum_with_db_name with_db_name); +int show_create_table_ex(THD *thd, TABLE_LIST *table_list, + const char * forced_db, const char *forced_name, + String *packet, + Table_specification_st *create_info_arg, + enum_with_db_name with_db_name); + int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); bool append_identifier(THD *thd, String *packet, const char *name, size_t length); @@ -113,6 +119,7 @@ bool append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user, const LEX_CSTRING *definer_host); int add_status_vars(SHOW_VAR *list); void remove_status_vars(SHOW_VAR *list); +ulonglong get_status_vars_version(void); void init_status_vars(); void free_status_vars(); void reset_status_vars(); diff --git a/sql/sql_sort.h b/sql/sql_sort.h index 2c01b01b607..5b3f5a67d17 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -20,8 +20,8 @@ #include "my_base.h" /* ha_rows */ #include <my_sys.h> /* qsort2_cmp */ #include "queues.h" +#include "sql_class.h" -struct SORT_FIELD; class Field; struct TABLE; @@ -156,6 +156,7 @@ public: }; typedef Bounds_checked_array<SORT_ADDON_FIELD> Addon_fields_array; +typedef Bounds_checked_array<SORT_FIELD> Sort_keys_array; /** This class wraps information about usage of addon fields. @@ -182,7 +183,7 @@ public: /// rr_unpack_from_tempfile needs an extra buffer when unpacking. uchar *allocate_addon_buf(uint sz) { - m_addon_buf= (uchar *)my_malloc(sz, MYF(MY_WME | MY_THREAD_SPECIFIC)); + m_addon_buf= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME | MY_THREAD_SPECIFIC)); if (m_addon_buf) m_addon_buf_length= sz; return m_addon_buf; @@ -241,22 +242,263 @@ private: bool m_using_packed_addons; ///< Are we packing the addon fields? }; +/** + This class wraps information about usage of sort keys. + A Sort_keys object is used both during packing of data in the filesort + buffer, and later during unpacking in 'Filesort_info::unpack_addon_fields'. + + @see SORT_FIELD struct. +*/ + +class Sort_keys :public Sql_alloc, + public Sort_keys_array +{ +public: + Sort_keys(SORT_FIELD* arr, size_t count): + Sort_keys_array(arr, count), + m_using_packed_sortkeys(false), + size_of_packable_fields(0), + sort_length(0) + { + DBUG_ASSERT(!is_null()); + } + + bool using_packed_sortkeys() const + { return m_using_packed_sortkeys; } + + void set_using_packed_sortkeys(bool val) + { + m_using_packed_sortkeys= val; + } + void set_size_of_packable_fields(uint len) + { + size_of_packable_fields= len; + } + + uint get_size_of_packable_fields() + { + return size_of_packable_fields; + } + + void set_sort_length(uint len) + { + sort_length= len; + } + + uint get_sort_length() + { + return sort_length; + } + + static void store_sortkey_length(uchar *p, uint sz) + { + int4store(p, sz - size_of_length_field); + } + + static uint read_sortkey_length(uchar *p) + { + return size_of_length_field + uint4korr(p); + } + + void increment_size_of_packable_fields(uint len) + { + size_of_packable_fields+= len; + } + + void increment_original_sort_length(uint len) + { + sort_length+= len; + } + + static const uint size_of_length_field= 4; + +private: + bool m_using_packed_sortkeys; // Are we packing sort keys + uint size_of_packable_fields; // Total length bytes for packable columns + + /* + The length that would be needed if we stored non-packed mem-comparable + images of fields? + */ + uint sort_length; +}; + + +/** +PACKED SORT KEYS + +Description + +In this optimization where we would like the pack the values of the sort key +inside the sort buffer for each record. + +Contents: +1. Background +1.1 Implementation details +2. Solution : Packed Sort Keys +2.1 Packed key format +2.2 Which format to use +3. Special cases +3.1 Handling very long strings +3.2 Handling for long binary strings +3.3 Handling very long strings with Packed sort keys +4. Sort key columns in addon_fields + +1. Background +Before this optimization of using packed sort keys, filesort() sorted the +data using mem-comparable keys. + +That is, if we wanted to sort by + + ORDER BY col1, col2, ... colN +then the filesort code would for each row generate one "Sort Key" +and then sort the rows by their Sort Keys. + +The Sort Keys are mem-comparable (that is, are compared by memcmp()) and +they are of FIXED SIZE. The sort key has the same length regardless of +what value it represents. This causes INEFFICIENT MEMORY USAGE. + +1.1 Implementation details + +make_sortkey() is the function that produces a sort key +from a record. + +The function treats Field and Item objects differently. + +class Field has: + +a) void make_sort_key(uchar *buff, uint length); + make_sort_key is a non-virtual function which handles encoding of + SQL null values. + +b) virtual void sort_string(uchar *buff,uint length)=0; + sort_string produces mem-comparable image of the field value + for each datatype. + +For Items, Type_handler has a virtual function: + + virtual void make_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const= 0; + which various datatypes overload. + + +2. SOLUTION: PACKED SORT KEYS + +Note that one can have mem-comparable keys are that are not fixed-size. +MyRocks uses such encoding for example. + +However for this optimization it was decided to store the original +(non-mem-comparable) values instead and use a datatype-aware +key comparison function. + +2.1 Packed key format +The keys are stored in a new variable-size data format called "packed". + +The format is as follows: + + <sort_key_length><packed_value_1><packed_value2> ....... <packed_valueN> + + format for a n-part sort key + +<sort_key_length> is the length of the whole key. +Each packed value is encoded as follows: + + <null_byte=0> // This is a an SQL NULL + [<null_byte=1>] <packed_value> // this a non-NULL value +null_byte is present if the field/item is NULLable. +SQL NULL is encoded as just one NULL-indicator byte. The value itself is omitted. + +The format of the packed_value depends on the datatype. +For "non-packable" datatypes it is just their mem-comparable form, as before. + +The "packable" datatypes are currently variable-length strings and the +packed format for them is (for binary blobs, see a note below): + +<length> <string> +2.2 Which format to use + +The advantage of Packed Key Format is potential space savings for +variable-length fields. + +The disadvantages are: + +a) It may actually take more space, because of sort_key_length and + length fields. +b) The comparison function is more expensive. + +Currently the logic is: use Packed Key Format if we would save 128 or more +bytes when constructing a sort key from values that have empty string +for each packable component. + +3. SPECIAL CASES +3.1 HANDLING VERY LONG STRINGS +the size of sort key part was limited by @@max_sort_length variable. +It is defined as: + +The number of bytes to use when sorting data values. The server uses only the +first max_sort_length bytes of each value and ignores the rest. + +3.2 HANDLING VERY LONG BINARY STRINGS +Long binary strings receive special treatment. A sort key for the long +binary string is truncated at max_sort_length bytes like described above, +but then a "suffix" is appended which contains the total length of the +value before the truncation. + +3.3 HANDLING VERY LONG STRINGS WITH PACKED SORT KEY +Truncating multi-byte string at N bytes is not safe because one can cut in the +middle of a character. One is tempted to solve this by discarding the partial +character but that's also not a good idea as in some collations multiple +characters may produce one weight (this is called "contraction"). + +This combination of circumstances: + +The string value is very long, so truncation is necessary +The collation is "complex", so truncation is dangerous +is deemed to be relatively rare so it was decided to just use +the non-packed sort keys in this case. + +4. SORT KEY COLUMNS IN ADDON FIELDS +Currently, each sort key column is actually stored twice +1. as part of the sort key +2. in the addon_fields +This made total sense when sort key stored the mem-comparable image +(from which one cannot restore the original value in general case). +But since we now store the original value, we could also remove it from the +addon_fields and further save space. This is still a limitation and needs +to be fixed later + +@see Sort_keys + +**/ /** - There are two record formats for sorting: - |<key a><key b>...|<rowid>| - / sort_length / ref_l / + The sort record format may use one of two formats for the non-sorted part of + the record: + + 1. Use the rowid + + |<sort_key>| <rowid> | + / / ref_length / - or with "addon fields" - |<key a><key b>...|<null bits>|<field a><field b>...| - / sort_length / addon_length / + 2. Use "addon fields" + + |<sort_key>|<null bits>|<field a><field b>...| + / / addon_length / The packed format for "addon fields" - |<key a><key b>...|<length>|<null bits>|<field a><field b>...| - / sort_length / addon_length / + + |<sort_key>|<length>|<null bits>|<field a><field b>...| + / / addon_length / + + <sort_key> The key may use one of the two formats: + A. fixed-size mem-comparable form. The record is always + sort_length bytes long. + B. "PackedKeyFormat" - the records are variable-size. <key> Fields are fixed-size, specially encoded with Field::make_sort_key() so we can do byte-by-byte compare. + <length> Contains the *actual* packed length (after packing) of everything after the sort keys. The size of the length field is 2 bytes, @@ -289,6 +531,7 @@ public: */ Bounds_checked_array<SORT_FIELD> local_sortorder; Addon_fields *addon_fields; // Descriptors for companion fields. + Sort_keys *sort_keys; bool using_pq; uchar *unique_buff; @@ -316,12 +559,59 @@ public: return m_using_packed_addons; } + bool using_packed_sortkeys() const + { + DBUG_ASSERT(m_using_packed_sortkeys == + (sort_keys != NULL && sort_keys->using_packed_sortkeys())); + return m_using_packed_sortkeys; + } + /// Are we using "addon fields"? bool using_addon_fields() const { return addon_fields != NULL; } + uint32 get_result_length(uchar *plen) + { + if (!m_using_packed_addons) + return res_length; + return Addon_fields::read_addon_length(plen); + } + + uint32 get_addon_length(uchar *plen) + { + if (using_packed_addons()) + return Addon_fields::read_addon_length(plen); + else + return addon_length; + } + + uint32 get_sort_length(uchar *plen) + { + if (using_packed_sortkeys()) + return Sort_keys::read_sortkey_length(plen) + + /* + when addon fields are not present, then the sort_length also + includes the res_length. For packed keys here we add + the res_length + */ + (using_addon_fields() ? 0: res_length); + else + return sort_length; + } + + uint get_record_length(uchar *plen) + { + if (m_packed_format) + { + uint sort_len= get_sort_length(plen); + return sort_len + get_addon_length(plen + sort_len); + } + else + return rec_length; + } + /** Getter for record length and result length. @param record_start Pointer to record. @@ -330,22 +620,46 @@ public: */ void get_rec_and_res_len(uchar *record_start, uint *recl, uint *resl) { - if (!using_packed_addons()) + if (m_packed_format) + { + uint sort_len= get_sort_length(record_start); + uint addon_len= get_addon_length(record_start + sort_len); + *recl= sort_len + addon_len; + *resl= using_addon_fields() ? addon_len : res_length; + } + else { *recl= rec_length; *resl= res_length; - return; } - uchar *plen= record_start + sort_length; - *resl= Addon_fields::read_addon_length(plen); - DBUG_ASSERT(*resl <= res_length); - const uchar *record_end= plen + *resl; - *recl= static_cast<uint>(record_end - record_start); + } + + void try_to_pack_sortkeys(); + + qsort2_cmp get_compare_function() const + { + return using_packed_sortkeys() ? + get_packed_keys_compare_ptr() : + get_ptr_compare(sort_length); + } + void* get_compare_argument(size_t *sort_len) const + { + return using_packed_sortkeys() ? + (void*) this : + (void*) sort_len; + } + + bool is_packed_format() const + { + return m_packed_format; } private: uint m_packable_length; bool m_using_packed_addons; ///< caches the value of using_packed_addons() + /* caches the value of using_packed_sortkeys() */ + bool m_using_packed_sortkeys; + bool m_packed_format; }; typedef Bounds_checked_array<uchar> Sort_buffer; @@ -353,7 +667,7 @@ typedef Bounds_checked_array<uchar> Sort_buffer; int merge_many_buff(Sort_param *param, Sort_buffer sort_buffer, Merge_chunk *buffpek, uint *maxbuffer, IO_CACHE *t_file); ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek, - Sort_param *param); + Sort_param *param, bool packing_format); bool merge_buffers(Sort_param *param,IO_CACHE *from_file, IO_CACHE *to_file, Sort_buffer sort_buffer, Merge_chunk *lastbuff, Merge_chunk *Fb, diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index a94fb1196b4..55e8e52c052 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1432,7 +1432,7 @@ public: */ bool init(uint n_keyparts) { - if (!(rowid_buf= (uchar*)my_malloc(rowid_size, MYF(0)))) + if (!(rowid_buf= (uchar*)my_malloc(PSI_INSTRUMENT_ME, rowid_size, MYF(0)))) return true; if (open_cached_file(&io_cache, mysql_tmpdir, TEMP_PREFIX, diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 4ddc467794f..2fc6ae0ad7d 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -41,8 +41,8 @@ bool Binary_string::real_alloc(size_t length) if (Alloced_length < arg_length) { free(); - if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME | - (thread_specific ? + if (!(Ptr=(char*) my_malloc(PSI_INSTRUMENT_ME, + arg_length,MYF(MY_WME | (thread_specific ? MY_THREAD_SPECIFIC : 0))))) return TRUE; DBUG_ASSERT(length < UINT_MAX32); @@ -92,13 +92,13 @@ bool Binary_string::realloc_raw(size_t alloc_length) return TRUE; /* Overflow */ if (alloced) { - if (!(new_ptr= (char*) my_realloc(Ptr,len, + if (!(new_ptr= (char*) my_realloc(PSI_INSTRUMENT_ME, Ptr,len, MYF(MY_WME | (thread_specific ? MY_THREAD_SPECIFIC : 0))))) return TRUE; // Signal error } - else if ((new_ptr= (char*) my_malloc(len, + else if ((new_ptr= (char*) my_malloc(PSI_INSTRUMENT_ME, len, MYF(MY_WME | (thread_specific ? MY_THREAD_SPECIFIC : 0))))) @@ -1236,3 +1236,25 @@ bool String::append_semi_hex(const char *s, uint len, CHARSET_INFO *cs) str_length+= nbytes; return false; } + +// Shrink the buffer, but only if it is allocated on the heap. +void Binary_string::shrink(size_t arg_length) +{ + if (!is_alloced()) + return; + if (ALIGN_SIZE(arg_length + 1) < Alloced_length) + { + char* new_ptr; + if (!(new_ptr = (char*)my_realloc(STRING_PSI_MEMORY_KEY, Ptr, arg_length, + MYF(thread_specific ? MY_THREAD_SPECIFIC : 0)))) + { + Alloced_length = 0; + real_alloc(arg_length); + } + else + { + Ptr = new_ptr; + Alloced_length = (uint32)arg_length; + } + } +} diff --git a/sql/sql_string.h b/sql/sql_string.h index eb69d21eaeb..4eeac0a8a82 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -30,6 +30,13 @@ #include "sql_list.h" class String; +#ifdef MYSQL_SERVER +extern PSI_memory_key key_memory_String_value; +#define STRING_PSI_MEMORY_KEY key_memory_String_value +#else +#define STRING_PSI_MEMORY_KEY PSI_NOT_INSTRUMENTED +#endif + typedef struct st_io_cache IO_CACHE; typedef struct st_mem_root MEM_ROOT; @@ -659,28 +666,8 @@ public: return realloc_with_extra(arg_length); } // Shrink the buffer, but only if it is allocated on the heap. - inline void shrink(size_t arg_length) - { - if (!is_alloced()) - return; - if (ALIGN_SIZE(arg_length+1) < Alloced_length) - { - char *new_ptr; - if (unlikely(!(new_ptr=(char*) - my_realloc(Ptr, - arg_length,MYF((thread_specific ? - MY_THREAD_SPECIFIC : 0)))))) - { - Alloced_length= 0; - real_alloc(arg_length); - } - else - { - Ptr= new_ptr; - Alloced_length= (uint32) arg_length; - } - } - } + void shrink(size_t arg_length); + void move(Binary_string &s) { set_alloced(s.Ptr, s.str_length, s.Alloced_length); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 240f001f7de..a499f91397a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1127,8 +1127,8 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) ddl_log_entry->tmp_name)); handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); - init_sql_alloc(&mem_root, "execute_ddl_log_action", TABLE_ALLOC_BLOCK_SIZE, - 0, MYF(MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_gdl, &mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, + MYF(MY_THREAD_SPECIFIC)); if (!strcmp(ddl_log_entry->handler_name, reg_ext)) frm_action= TRUE; else @@ -1162,7 +1162,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) } #ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(to_path, ddl_log_entry->name, par_ext, NullS); - (void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME)); + (void) mysql_file_delete(key_file_partition_ddl_log, to_path, MYF(MY_WME)); #endif } else @@ -1200,7 +1200,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) #ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(to_path, ddl_log_entry->name, par_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); - (void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME)); + (void) mysql_file_rename(key_file_partition_ddl_log, from_path, to_path, MYF(MY_WME)); #endif } else @@ -1297,7 +1297,7 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, if (global_ddl_log.first_free == NULL) { - if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( + if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(key_memory_DDL_LOG_MEMORY_ENTRY, sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { sql_print_error("Failed to allocate memory for ddl log free list"); @@ -6167,7 +6167,7 @@ drop_create_field: for (f_ptr=table->field; *f_ptr; f_ptr++) { if (my_strcasecmp(system_charset_info, - acol->name, (*f_ptr)->field_name.str) == 0) + acol->name.str, (*f_ptr)->field_name.str) == 0) break; } if (unlikely(*f_ptr == NULL)) @@ -6175,7 +6175,7 @@ drop_create_field: push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_BAD_FIELD_ERROR, ER_THD(thd, ER_BAD_FIELD_ERROR), - acol->name, table->s->table_name.str); + acol->name.str, table->s->table_name.str); it.remove(); if (alter_info->alter_list.is_empty()) { @@ -6601,7 +6601,7 @@ static int compare_uint(const uint *s, const uint *t) enum class Compare_keys : uint32_t { - Equal, + Equal= 0, EqualButKeyPartLength, EqualButComment, NotEqual @@ -7998,6 +7998,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, List<Create_field> new_create_list; /* New key definitions are added here */ List<Key> new_key_list; + List<Alter_rename_key> rename_key_list(alter_info->alter_rename_key_list); List_iterator<Alter_drop> drop_it(alter_info->drop_list); List_iterator<Create_field> def_it(alter_info->create_list); List_iterator<Alter_column> alter_it(alter_info->alter_list); @@ -8138,24 +8139,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, continue; } - /* - If we are doing a rename of a column, update all references in virtual - column expressions, constraints and defaults to use the new column name - */ - if (alter_info->flags & ALTER_RENAME_COLUMN) - { - if (field->vcol_info) - field->vcol_info->expr->walk(&Item::rename_fields_processor, 1, - &column_rename_param); - if (field->check_constraint) - field->check_constraint->expr->walk(&Item::rename_fields_processor, 1, - &column_rename_param); - if (field->default_value) - field->default_value->expr->walk(&Item::rename_fields_processor, 1, - &column_rename_param); - table->m_needs_reopen= 1; // because new column name is on thd->mem_root - } - /* Check if field is changed */ def_it.rewind(); while ((def=def_it++)) @@ -8229,19 +8212,61 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, while ((alter=alter_it++)) { if (!my_strcasecmp(system_charset_info,field->field_name.str, - alter->name)) + alter->name.str)) break; } if (alter) { - if ((def->default_value= alter->default_value)) - def->flags&= ~NO_DEFAULT_VALUE_FLAG; + if (alter->is_rename()) + { + def->change= alter->name; + def->field_name= alter->new_name; + column_rename_param.fields.push_back(def); + } else - def->flags|= NO_DEFAULT_VALUE_FLAG; + { + if ((def->default_value= alter->default_value)) + def->flags&= ~NO_DEFAULT_VALUE_FLAG; + else + def->flags|= NO_DEFAULT_VALUE_FLAG; + } alter_it.remove(); } } } + + /* + If we are doing a rename of a column, update all references in virtual + column expressions, constraints and defaults to use the new column name + */ + if (alter_info->flags & ALTER_RENAME_COLUMN) + { + alter_it.rewind(); + Alter_column *alter; + while ((alter=alter_it++)) + { + if (alter->is_rename()) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), alter->name.str, + table->s->table_name.str); + goto err; + } + } + for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) + { + if (field->vcol_info) + field->vcol_info->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->check_constraint) + field->check_constraint->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->default_value) + field->default_value->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + } + table->m_needs_reopen= 1; // because new column name is on thd->mem_root + } + dropped_sys_vers_fields &= VERS_SYSTEM_FIELD; if ((dropped_sys_vers_fields || alter_info->flags & ALTER_DROP_PERIOD) && @@ -8357,7 +8382,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, while ((alter=alter_it++)) { if (!my_strcasecmp(system_charset_info,def->field_name.str, - alter->name)) + alter->name.str)) break; } if (alter) @@ -8372,7 +8397,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (unlikely(alter_info->alter_list.elements)) { my_error(ER_BAD_FIELD_ERROR, MYF(0), - alter_info->alter_list.head()->name, table->s->table_name.str); + alter_info->alter_list.head()->name.str, table->s->table_name.str); goto err; } if (unlikely(!new_create_list.elements)) @@ -8422,6 +8447,39 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, continue; } + /* If this index is to stay in the table check if it has to be renamed. */ + List_iterator<Alter_rename_key> rename_key_it(rename_key_list); + Alter_rename_key *rename_key; + + while ((rename_key= rename_key_it++)) + { + if (!my_strcasecmp(system_charset_info, key_name, rename_key->old_name.str)) + { + if (!my_strcasecmp(system_charset_info, key_name, primary_key_name)) + { + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->old_name.str); + goto err; + } + else if (!my_strcasecmp(system_charset_info, rename_key->new_name.str, + primary_key_name)) + { + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->new_name.str); + goto err; + } + + key_name= rename_key->new_name.str; + rename_key_it.remove(); + /* + If the user has explicitly renamed the key, we should no longer + treat it as generated. Otherwise this key might be automatically + dropped by mysql_prepare_create_table() and this will confuse + code in fill_alter_inplace_info(). + */ + key_info->flags&= ~HA_GENERATED_KEY; + break; + } + } + if (key_info->algorithm == HA_KEY_ALG_LONG_HASH) { setup_keyinfo_hash(key_info); @@ -8748,6 +8806,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } } + if (rename_key_list.elements) + { + my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), rename_key_list.head()->old_name.str, + table->s->table_name.str); + goto err; + } + if (!create_info->comment.str) { create_info->comment.str= table->s->comment.str; @@ -9140,8 +9205,8 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, ref_table= tbuf; } - mdl_request.init(MDL_key::TABLE, ref_db, ref_table, MDL_SHARED_NO_WRITE, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, ref_db, ref_table, + MDL_SHARED_NO_WRITE, MDL_TRANSACTION); if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) DBUG_RETURN(true); @@ -9566,9 +9631,9 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, MDL_request_list mdl_requests; MDL_request target_db_mdl_request; - target_mdl_request.init(MDL_key::TABLE, - alter_ctx.new_db.str, alter_ctx.new_name.str, - MDL_EXCLUSIVE, MDL_TRANSACTION); + MDL_REQUEST_INIT(&target_mdl_request, MDL_key::TABLE, + alter_ctx.new_db.str, alter_ctx.new_name.str, + MDL_EXCLUSIVE, MDL_TRANSACTION); mdl_requests.push_front(&target_mdl_request); /* @@ -9578,9 +9643,9 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, */ if (alter_ctx.is_database_changed()) { - target_db_mdl_request.init(MDL_key::SCHEMA, alter_ctx.new_db.str, "", - MDL_INTENTION_EXCLUSIVE, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&target_db_mdl_request, MDL_key::SCHEMA, + alter_ctx.new_db.str, "", MDL_INTENTION_EXCLUSIVE, + MDL_TRANSACTION); mdl_requests.push_front(&target_db_mdl_request); } @@ -9827,8 +9892,7 @@ do_continue:; bool fast_alter_partition= false; { if (prep_alter_part_table(thd, table, alter_info, create_info, - &alter_ctx, &partition_changed, - &fast_alter_partition)) + &partition_changed, &fast_alter_partition)) { DBUG_RETURN(true); } @@ -10680,6 +10744,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE); to->file->ha_start_bulk_insert(from->file->stats.records, ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); + mysql_stage_set_work_estimated(thd->m_stage_progress_psi, from->file->stats.records); + List_iterator<Create_field> it(create); Create_field *def; copy_end=copy; @@ -10780,7 +10846,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, from->file->column_bitmaps_signal(); - THD_STAGE_INFO(thd, stage_copy_to_tmp_table); /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); /* Add virtual columns to vcol_set to ensure they are updated */ @@ -10926,7 +10991,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, } } else + { + DEBUG_SYNC(thd, "copy_data_between_tables_before"); found_count++; + mysql_stage_set_work_completed(thd->m_stage_progress_psi, found_count); + } thd->get_stmt_da()->inc_current_row_for_warning(); } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 07e2d5e084e..ffd42599527 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -466,7 +466,8 @@ static void display_table_locks(void) void *saved_base; DYNAMIC_ARRAY saved_table_locks; - (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), + (void) my_init_dynamic_array(key_memory_locked_thread_list, + &saved_table_locks, sizeof(TABLE_LOCK_INFO), tc_records() + 20, 50, MYF(0)); mysql_mutex_lock(&THR_LOCK_lock); for (list= thr_lock_thread_list; list; list= list_rest(list)) diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 8a9311ae577..c08e54bed87 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -830,7 +830,8 @@ DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format) if (thd) new_format= (DATE_TIME_FORMAT *) thd->alloc(length); else - new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME)); + new_format= (DATE_TIME_FORMAT *) my_malloc(key_memory_DATE_TIME_FORMAT, + length, MYF(MY_WME)); if (new_format) { /* Put format string after current pos */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 0ae3d58b11f..5b8ae46d33f 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -30,11 +30,11 @@ #include "sql_table.h" // build_table_filename, // check_n_cut_mysql50_prefix #include "sql_db.h" // get_default_db_collation -#include "sql_acl.h" // *_ACL #include "sql_handler.h" // mysql_ha_rm_tables #include "sp_cache.h" // sp_invalidate_cache #include <mysys_err.h> #include "debug_sync.h" +#include "mysql/psi/mysql_sp.h" /*************************************************************************/ @@ -440,7 +440,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ if (!trust_function_creators && (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && - !(thd->security_ctx->master_access & SUPER_ACL)) + !(thd->security_ctx->master_access & PRIV_LOG_BIN_TRUSTED_SP_CREATOR)) { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); @@ -463,7 +463,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ thd->lex->sql_command= backup.sql_command; - if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && + if (opt_readonly && + !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && !thd->slave_thread) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); @@ -624,7 +625,13 @@ end: thd->lex->restore_backup_query_tables_list(&backup); if (!result) + { my_ok(thd); + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(SP_TYPE_TRIGGER, + thd->lex->spname->m_db.str, static_cast<uint>(thd->lex->spname->m_db.length), + thd->lex->spname->m_name.str, static_cast<uint>(thd->lex->spname->m_name.length)); + } DBUG_RETURN(result); #ifdef WITH_WSREP @@ -1554,6 +1561,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, trigger->definer= *trg_definer; } + sp->m_sp_share= MYSQL_GET_SP_SHARE(SP_TYPE_TRIGGER, + sp->m_db.str, static_cast<uint>(sp->m_db.length), + sp->m_name.str, static_cast<uint>(sp->m_name.length)); + #ifndef DBUG_OFF /* Let us check that we correctly update trigger definitions when we @@ -1813,8 +1824,8 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db, DBUG_ENTER("Triggers::drop_all_triggers"); table.reset(); - init_sql_alloc(&table.mem_root, "Triggers::drop_all_triggers", 8192, 0, - MYF(0)); + init_sql_alloc(key_memory_Table_trigger_dispatcher, + &table.mem_root, 8192, 0, MYF(0)); if (Table_triggers_list::check_n_load(thd, db, name, &table, 1)) { @@ -1846,6 +1857,9 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db, */ result= 1; } + /* Drop statistics for this stored program from performance schema. */ + MYSQL_DROP_SP(SP_TYPE_TRIGGER, db->str, static_cast<uint>(db->length), + trigger->name.str, static_cast<uint>(trigger->name.length)); } } } @@ -2065,8 +2079,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db, DBUG_ENTER("Triggers::change_table_name"); table.reset(); - init_sql_alloc(&table.mem_root, "Triggers::change_table_name", 8192, 0, - MYF(0)); + init_sql_alloc(key_memory_Table_trigger_dispatcher, + &table.mem_root, 8192, 0, MYF(0)); /* This method interfaces the mysql server code protected by diff --git a/sql/sql_type.h b/sql/sql_type.h index ce87c8e9d93..f87e398bd71 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -23,6 +23,7 @@ #include "mysqld.h" +#include "lex_string.h" #include "sql_array.h" #include "sql_const.h" #include "sql_time.h" @@ -86,6 +87,7 @@ class handler; struct Schema_specification_st; struct TABLE; struct SORT_FIELD_ATTR; +struct SORT_FIELD; class Vers_history_point; class Virtual_column_info; class Conv_source; @@ -137,6 +139,41 @@ enum column_definition_type_t }; +class Send_field_extended_metadata +{ + LEX_CSTRING m_attr[MARIADB_FIELD_ATTR_LAST+1]; +public: + Send_field_extended_metadata() + { + bzero(this, sizeof(*this)); + } + bool set_data_type_name(const LEX_CSTRING &str) + { + m_attr[MARIADB_FIELD_ATTR_DATA_TYPE_NAME]= str; + return false; + } + bool set_format_name(const LEX_CSTRING &str) + { + m_attr[MARIADB_FIELD_ATTR_FORMAT_NAME]= str; + return false; + } + bool has_extended_metadata() const + { + for (uint i= 0; i <= MARIADB_FIELD_ATTR_LAST; i++) + { + if (m_attr[i].str) + return true; + } + return false; + } + const LEX_CSTRING &attr(uint i) const + { + DBUG_ASSERT(i <= MARIADB_FIELD_ATTR_LAST); + return m_attr[i]; + } +}; + + class Data_type_statistics { public: @@ -3332,6 +3369,14 @@ protected: bool maybe_null, bool null_value, bool unsigned_flag, longlong value) const; + void store_sort_key_longlong(uchar *to, bool unsigned_flag, + longlong value) const; + + uint make_packed_sort_key_longlong(uchar *to, bool maybe_null, + bool null_value, bool unsigned_flag, + longlong value, + const SORT_FIELD_ATTR *sort_field) const; + bool Item_func_or_sum_illegal_param(const char *name) const; bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; bool check_null(const Item *item, st_value *value) const; @@ -3426,6 +3471,11 @@ public: return field_type(); } virtual protocol_send_type_t protocol_send_type() const= 0; + virtual bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const + { + return false; + } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; virtual enum_dynamic_column_type @@ -3752,12 +3802,25 @@ public: const uchar *buffer, LEX_CUSTRING *gis_options) const; - virtual void make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const= 0; - virtual void sortlength(THD *thd, + /* + Create a fixed size key part for a sort key + */ + virtual void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const= 0; + + /* + create a compact size key part for a sort key + */ + virtual uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const=0; + + virtual void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; + virtual bool is_packable() const { return false; } + virtual uint32 max_display_length(const Item *item) const= 0; virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; } @@ -4149,14 +4212,21 @@ public: const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; - void make_sort_key(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override { DBUG_ASSERT(0); } - void sortlength(THD *thd, const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override + { + DBUG_ASSERT(0); + return 0; + } + void sort_length(THD *thd, const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override { DBUG_ASSERT(0); } @@ -4481,11 +4551,15 @@ public: bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, @@ -4588,8 +4662,12 @@ public: bool show_field) const override; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; @@ -4599,9 +4677,9 @@ public: const uchar *buffer, LEX_CUSTRING *gis_options) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; Item *create_typecast_item(THD *thd, Item *item, @@ -4838,14 +4916,18 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, @@ -4945,11 +5027,15 @@ public: void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_param_set_from_value(THD *thd, @@ -5034,11 +5120,16 @@ public: const Type_handler * type_handler_adjusted_to_max_octet_length(uint max_octet_length, CHARSET_INFO *cs) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; + bool is_packable()const override { return true; } bool union_element_finalize(const Item * item) const override; uint calc_key_length(const Column_definition &def) const override; bool Column_definition_prepare_stage1(THD *thd, @@ -6230,11 +6321,15 @@ public: cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const override; - void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - Sort_param *param) const override; - void sortlength(THD *thd, - const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override; + void make_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; + void sort_length(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; uint Item_decimal_scale(const Item *item) const override { @@ -7192,7 +7287,7 @@ private: const Type_handler *handler2) const; public: Type_aggregator(bool is_commutative= false) - :m_is_commutative(is_commutative) + :m_is_commutative(is_commutative), m_array(PSI_INSTRUMENT_MEM) { } bool add(const Type_handler *handler1, const Type_handler *handler2, diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc index 3ca0eaabc3f..0dcde0009b0 100644 --- a/sql/sql_type_geom.cc +++ b/sql/sql_type_geom.cc @@ -34,6 +34,14 @@ Named_type_handler<Type_handler_geometrycollection> type_handler_geometrycollect Type_collection_geometry type_collection_geometry; + +LEX_CSTRING Type_handler_geometry::extended_metadata_data_type_name() const +{ + return geometry_type() == GEOM_GEOMETRY ? null_clex_str : + name().lex_cstring(); +} + + const Type_handler_geometry * Type_handler_geometry::type_handler_geom_by_type(uint type) { diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h index a2baa5ae299..b1aa8063902 100644 --- a/sql/sql_type_geom.h +++ b/sql/sql_type_geom.h @@ -39,9 +39,16 @@ public: Item * const *args, uint start, uint end); static const Type_handler_geometry *type_handler_geom_by_type(uint type); + LEX_CSTRING extended_metadata_data_type_name() const; public: virtual ~Type_handler_geometry() {} enum_field_types field_type() const override { return MYSQL_TYPE_GEOMETRY; } + bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const override + { + LEX_CSTRING tmp= extended_metadata_data_type_name(); + return tmp.length ? to->set_data_type_name(tmp) : false; + } bool is_param_long_data_type() const override { return true; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; @@ -361,6 +368,9 @@ public: void make_send_field(Send_field *to) override { Field_longstr::make_send_field(to); + LEX_CSTRING tmp= m_type_handler->extended_metadata_data_type_name(); + if (tmp.length) + to->set_data_type_name(tmp); } bool can_optimize_range(const Item_bool_func *cond, const Item *item, diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 35c799d4a86..4da85de7852 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -110,6 +110,8 @@ extern "C" uchar* get_hash_key(const uchar *buff, size_t *length, return (uchar*) udf->name.str; } +static PSI_memory_key key_memory_udf_mem; + #ifdef HAVE_PSI_INTERFACE static PSI_rwlock_key key_rwlock_THR_LOCK_udf; @@ -118,6 +120,11 @@ static PSI_rwlock_info all_udf_rwlocks[]= { &key_rwlock_THR_LOCK_udf, "THR_LOCK_udf", PSI_FLAG_GLOBAL} }; +static PSI_memory_info all_udf_memory[]= +{ + { &key_memory_udf_mem, "udf_mem", PSI_FLAG_GLOBAL} +}; + static void init_udf_psi_keys(void) { const char* category= "sql"; @@ -128,6 +135,9 @@ static void init_udf_psi_keys(void) count= array_elements(all_udf_rwlocks); PSI_server->register_rwlock(category, all_udf_rwlocks, count); + + count= array_elements(all_udf_memory); + mysql_memory_register(category, all_udf_memory, count); } #endif @@ -154,10 +164,11 @@ void udf_init() mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf); - init_sql_alloc(&mem, "udf", UDF_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_udf_mem, &mem, UDF_ALLOC_BLOCK_SIZE, 0, MYF(0)); THD *new_thd = new THD(0); if (!new_thd || - my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0)) + my_hash_init(key_memory_udf_mem, + &udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0)) { sql_print_error("Can't allocate memory for udf structures"); my_hash_free(&udf_hash); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index d5d43e56875..f8025cdf701 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -257,6 +257,8 @@ int select_union_recursive::send_data(List<Item> &values) write_err != HA_ERR_FOUND_DUPP_UNIQUE) { int err; + DBUG_ASSERT(incr_table->s->reclength == table->s->reclength || + incr_table->s->reclength == table->s->reclength - MARIA_UNIQUE_HASH_LENGTH); if ((err= incr_table->file->ha_write_tmp_row(table->record[0]))) { bool is_duplicate; @@ -1561,7 +1563,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg, { if (with_element) { - if (with_element->rename_columns_of_derived_unit(thd, this)) + if (with_element->process_columns_of_derived_unit(thd, this)) goto err; if (check_duplicate_names(thd, sl->item_list, 0)) goto err; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6d6958ba50b..d0a920fd473 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -35,7 +35,6 @@ #include "probes_mysql.h" #include "debug_sync.h" #include "key.h" // is_key_used -#include "sql_acl.h" // *_ACL, check_grant #include "records.h" // init_read_record, // end_read_record #include "filesort.h" // filesort diff --git a/sql/sql_view.cc b/sql/sql_view.cc index f47e910c0fe..b2e977151fd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -27,7 +27,6 @@ #include "sql_show.h" // append_identifier #include "sql_table.h" // build_table_filename #include "sql_db.h" // mysql_opt_change_db, mysql_change_db -#include "sql_acl.h" // *_ACL, check_grant #include "sql_select.h" #include "parse_file.h" #include "sp_head.h" @@ -138,7 +137,7 @@ bool check_duplicate_names(THD *thd, List<Item> &item_list, bool gen_unique_view Item *check; /* treat underlying fields like set by user names */ if (item->real_item()->type() == Item::FIELD_ITEM) - item->is_autogenerated_name= FALSE; + item->common_flags&= ~IS_AUTO_GENERATED_NAME; itc.rewind(); while ((check= itc++) && check != item) { @@ -146,9 +145,9 @@ bool check_duplicate_names(THD *thd, List<Item> &item_list, bool gen_unique_view { if (!gen_unique_view_name) goto err; - if (item->is_autogenerated_name) + if (item->is_autogenerated_name()) make_unique_view_field_name(thd, item, item_list, item); - else if (check->is_autogenerated_name) + else if (check->is_autogenerated_name()) make_unique_view_field_name(thd, check, item_list, item); else goto err; @@ -180,7 +179,7 @@ void make_valid_column_names(THD *thd, List<Item> &item_list) for (uint column_no= 1; (item= it++); column_no++) { - if (!item->is_autogenerated_name || !check_column_name(item->name.str)) + if (!item->is_autogenerated_name() || !check_column_name(item->name.str)) continue; name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no); item->orig_name= item->name.str; @@ -566,7 +565,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, while ((item= it++, name= nm++)) { item->set_name(thd, *name); - item->is_autogenerated_name= FALSE; + item->common_flags&= ~IS_AUTO_GENERATED_NAME; } } diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 7e319c96000..a9a1dccf9f6 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -778,10 +778,10 @@ public: { //DBUG_ASSERT(info->read_record == rr_from_tempfile); rownum= 0; - io_cache= (IO_CACHE*)my_malloc(sizeof(IO_CACHE), MYF(0)); + io_cache= (IO_CACHE*)my_malloc(PSI_INSTRUMENT_ME, sizeof(IO_CACHE), MYF(0)); init_slave_io_cache(info->io_cache, io_cache); - ref_buffer= (uchar*)my_malloc(ref_length, MYF(0)); + ref_buffer= (uchar*)my_malloc(PSI_INSTRUMENT_ME, ref_length, MYF(0)); ref_buffer_valid= false; } } @@ -2816,7 +2816,7 @@ bool compute_window_func(THD *thd, List_iterator_fast<Group_bound_tracker> iter_part_trackers(partition_trackers); ha_rows rownum= 0; - uchar *rowid_buf= (uchar*) my_malloc(tbl->file->ref_length, MYF(0)); + uchar *rowid_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, tbl->file->ref_length, MYF(0)); while (true) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f24da3ed412..3f0f7251d5c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -38,7 +38,6 @@ #include "sql_parse.h" /* comp_*_creator */ #include "sql_table.h" /* primary_key_name */ #include "sql_partition.h" /* partition_info, HASH_PARTITION */ -#include "sql_acl.h" /* *_ACL */ #include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */ #include "slave.h" #include "lex_symbol.h" @@ -835,6 +834,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ %token <kwd> EXTENT_SIZE_SYM %token <kwd> FAST_SYM %token <kwd> FAULTS_SYM +%token <kwd> FEDERATED_SYM /* MariaDB privilege */ %token <kwd> FILE_SYM %token <kwd> FIRST_SYM /* SQL-2003-N */ %token <kwd> FIXED_SYM @@ -931,6 +931,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ %token <kwd> MIN_ROWS %token <kwd> MODE_SYM %token <kwd> MODIFY_SYM +%token <kwd> MONITOR_SYM /* MariaDB privilege */ %token <kwd> MONTH_SYM /* SQL-2003-R */ %token <kwd> MUTEX_SYM %token <kwd> MYSQL_SYM @@ -1749,6 +1750,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ comma_separated_ident_list opt_with_column_list with_column_list + opt_cycle %type <vers_range_unit> opt_history_unit %type <vers_history_point> history_point @@ -7705,13 +7707,12 @@ alter_list_item: } | ALTER opt_column opt_if_exists_table_element field_ident SET DEFAULT column_default_expr { - if (unlikely(Lex->add_alter_list($4.str, $7, $3))) + if (unlikely(Lex->add_alter_list($4, $7, $3))) MYSQL_YYABORT; } | ALTER opt_column opt_if_exists_table_element field_ident DROP DEFAULT { - if (unlikely(Lex->add_alter_list($4.str, (Virtual_column_info*) 0, - $3))) + if (unlikely(Lex->add_alter_list($4, (Virtual_column_info*) 0, $3))) MYSQL_YYABORT; } | RENAME opt_to table_ident @@ -7728,6 +7729,21 @@ alter_list_item: lex->name= $3->table; lex->alter_info.flags|= ALTER_RENAME; } + | RENAME COLUMN_SYM ident TO_SYM ident + { + if (unlikely(Lex->add_alter_list($3, $5))) + MYSQL_YYABORT; + } + | RENAME key_or_index field_ident TO_SYM field_ident + { + LEX *lex=Lex; + Alter_rename_key *ak= new (thd->mem_root) + Alter_rename_key($3, $5); + if (ak == NULL) + MYSQL_YYABORT; + lex->alter_info.alter_rename_key_list.push_back(ak); + lex->alter_info.flags|= ALTER_RENAME_INDEX; + } | CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate { if (!$4) @@ -9062,7 +9078,7 @@ select_item: if (unlikely(Lex->sql_command == SQLCOM_CREATE_VIEW && check_column_name($4.str))) my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str)); - $2->is_autogenerated_name= FALSE; + $2->common_flags&= ~IS_AUTO_GENERATED_NAME; $2->set_name(thd, $4); } else if (!$2->name.str || $2->name.str == item_empty_name) @@ -10624,7 +10640,7 @@ udf_expr: */ if ($4.str) { - $2->is_autogenerated_name= FALSE; + $2->common_flags&= ~IS_AUTO_GENERATED_NAME; $2->set_name(thd, $4); } /* @@ -12330,7 +12346,7 @@ int_num: ulong_num: opt_plus NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } - | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); } + | HEX_NUM { $$= strtoul($1.str, (char**) 0, 16); } | opt_plus LONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } | opt_plus ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } | opt_plus DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } @@ -13605,9 +13621,13 @@ show_param: MYSQL_YYABORT; lex->table_type= TABLE_TYPE_SEQUENCE; } + | BINLOG_SYM STATUS_SYM + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; + } | MASTER_SYM STATUS_SYM { - Lex->sql_command = SQLCOM_SHOW_MASTER_STAT; + Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; } | ALL SLAVES STATUS_SYM { @@ -14735,7 +14755,7 @@ with_list: with_list_element: query_name opt_with_column_list - AS '(' query_expression ')' + AS '(' query_expression ')' opt_cycle { LEX *lex= thd->lex; const char *query_start= lex->sphead ? lex->sphead->m_tmp_query @@ -14747,9 +14767,30 @@ with_list_element: if (elem->set_unparsed_spec(thd, spec_start, $6.pos(), spec_start - query_start)) MYSQL_YYABORT; + if ($7) + { + elem->set_cycle_list($7); + } } ; +opt_cycle: + /* empty */ + { $$= NULL; } + | + CYCLE_SYM + { + if (!Lex->curr_with_clause->with_recursive) + { + thd->parse_error(ER_SYNTAX_ERROR, $1.pos()); + } + } + comma_separated_ident_list RESTRICT + { + $$= $3; + } + ; + opt_with_column_list: /* empty */ @@ -15476,6 +15517,7 @@ keyword_sp_var_and_label: | FAST_SYM | FOUND_SYM | ENABLE_SYM + | FEDERATED_SYM | FULL | FILE_SYM | FIRST_SYM @@ -15554,6 +15596,7 @@ keyword_sp_var_and_label: | MIN_ROWS | MODIFY_SYM | MODE_SYM + | MONITOR_SYM | MONTH_SYM | MUTEX_SYM | MYSQL_SYM @@ -16862,7 +16905,7 @@ object_privilege: | CREATE TEMPORARY TABLES { $$= CREATE_TMP_ACL;} | LOCK_SYM TABLES { $$= LOCK_TABLES_ACL; } | REPLICATION SLAVE { $$= REPL_SLAVE_ACL; } - | REPLICATION CLIENT_SYM { $$= REPL_CLIENT_ACL; } + | REPLICATION CLIENT_SYM { $$= BINLOG_MONITOR_ACL; /*Compatibility*/ } | CREATE VIEW_SYM { $$= CREATE_VIEW_ACL; } | SHOW VIEW_SYM { $$= SHOW_VIEW_ACL; } | CREATE ROUTINE_SYM { $$= CREATE_PROC_ACL; } @@ -16872,6 +16915,15 @@ object_privilege: | TRIGGER_SYM { $$= TRIGGER_ACL; } | CREATE TABLESPACE { $$= CREATE_TABLESPACE_ACL; } | DELETE_SYM HISTORY_SYM { $$= DELETE_HISTORY_ACL; } + | SET USER_SYM { $$= SET_USER_ACL; } + | FEDERATED_SYM ADMIN_SYM { $$= FEDERATED_ADMIN_ACL; } + | CONNECTION_SYM ADMIN_SYM { $$= CONNECTION_ADMIN_ACL; } + | READ_SYM ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; } + | READ_ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; } + | BINLOG_SYM MONITOR_SYM { $$= BINLOG_MONITOR_ACL; } + | BINLOG_SYM ADMIN_SYM { $$= BINLOG_ADMIN_ACL; } + | REPLICATION MASTER_SYM ADMIN_SYM { $$= REPL_MASTER_ADMIN_ACL; } + | REPLICATION SLAVE ADMIN_SYM { $$= REPL_SLAVE_ADMIN_ACL; } ; opt_and: @@ -17539,7 +17591,10 @@ xid: } | text_string ',' text_string ',' ulong_num { - MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); + MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && + $3->length() <= MAXBQUALSIZE && + $5 <= static_cast<ulong>( + std::numeric_limits<int32_t>::max())); if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID))))) MYSQL_YYABORT; Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length()); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 4ba866749ee..15b749dcb61 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -45,8 +45,7 @@ #include "mysqld.h" #include "lock.h" #include "sql_time.h" // known_date_time_formats -#include "sql_acl.h" // SUPER_ACL, - // mysql_user_table_is_in_short_password_format +#include "sql_acl.h" // mysql_user_table_is_in_short_password_format #include "derror.h" // read_texts #include "sql_base.h" // close_cached_tables #include "hostname.h" // host_cache_size @@ -81,8 +80,7 @@ #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE static Sys_var_mybool Sys_pfs_enabled( - "performance_schema", - "Enable the performance schema.", + "performance_schema", "Enable the performance schema.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_enabled), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); @@ -90,10 +88,9 @@ static Sys_var_long Sys_pfs_events_waits_history_long_size( "performance_schema_events_waits_history_long_size", "Number of rows in EVENTS_WAITS_HISTORY_LONG." " Use 0 to disable, -1 for automated sizing.", - PARSED_EARLY READ_ONLY - GLOBAL_VAR(pfs_param.m_events_waits_history_long_sizing), + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_long_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_waits_history_size( "performance_schema_events_waits_history_size", @@ -101,7 +98,7 @@ static Sys_var_long Sys_pfs_events_waits_history_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_cond_classes( "performance_schema_max_cond_classes", @@ -116,7 +113,23 @@ static Sys_var_long Sys_pfs_max_cond_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_cond_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_program_instances( + "performance_schema_max_program_instances", + "Maximum number of instrumented programs." + " Use 0 to disable, -1 for automated scaling.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_program_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_prepared_stmt_instances( + "performance_schema_max_prepared_statements_instances", + "Maximum number of instrumented prepared statements." + " Use 0 to disable, -1 for automated scaling.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_prepared_stmt_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_file_classes( "performance_schema_max_file_classes", @@ -138,7 +151,7 @@ static Sys_var_long Sys_pfs_max_file_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_file_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_max_sockets( "performance_schema_max_socket_instances", @@ -146,16 +159,14 @@ static Sys_var_long Sys_pfs_max_sockets( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_socket_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_socket_classes( "performance_schema_max_socket_classes", "Maximum number of socket instruments.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_socket_class_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256), - DEFAULT(PFS_MAX_SOCKET_CLASS), - BLOCK_SIZE(1)); + DEFAULT(PFS_MAX_SOCKET_CLASS), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_mutex_classes( "performance_schema_max_mutex_classes", @@ -170,7 +181,7 @@ static Sys_var_long Sys_pfs_max_mutex_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_mutex_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_rwlock_classes( "performance_schema_max_rwlock_classes", @@ -185,7 +196,7 @@ static Sys_var_long Sys_pfs_max_rwlock_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_rwlock_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_max_table_handles( "performance_schema_max_table_handles", @@ -193,7 +204,7 @@ static Sys_var_long Sys_pfs_max_table_handles( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_max_table_instances( "performance_schema_max_table_instances", @@ -201,7 +212,23 @@ static Sys_var_long Sys_pfs_max_table_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_share_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_table_lock_stat( + "performance_schema_max_table_lock_stat", + "Maximum number of lock statistics for instrumented tables." + " Use 0 to disable, -1 for automated scaling.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_lock_stat_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_index_stat( + "performance_schema_max_index_stat", + "Maximum number of index statistics for instrumented tables." + " Use 0 to disable, -1 for automated scaling.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_index_stat_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_thread_classes( "performance_schema_max_thread_classes", @@ -216,23 +243,21 @@ static Sys_var_long Sys_pfs_max_thread_instances( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_thread_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); -static Sys_var_ulong Sys_pfs_setup_actors_size( +static Sys_var_long Sys_pfs_setup_actors_size( "performance_schema_setup_actors_size", "Maximum number of rows in SETUP_ACTORS.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_setup_actor_sizing), - CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024), - DEFAULT(PFS_MAX_SETUP_ACTOR), - BLOCK_SIZE(1)); + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); -static Sys_var_ulong Sys_pfs_setup_objects_size( +static Sys_var_long Sys_pfs_setup_objects_size( "performance_schema_setup_objects_size", "Maximum number of rows in SETUP_OBJECTS.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_setup_object_sizing), - CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), - DEFAULT(PFS_MAX_SETUP_OBJECT), - BLOCK_SIZE(1)); + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_accounts_size( "performance_schema_accounts_size", @@ -240,8 +265,7 @@ static Sys_var_long Sys_pfs_accounts_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_account_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_hosts_size( "performance_schema_hosts_size", @@ -249,8 +273,7 @@ static Sys_var_long Sys_pfs_hosts_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_host_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_users_size( "performance_schema_users_size", @@ -258,16 +281,14 @@ static Sys_var_long Sys_pfs_users_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_user_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_ulong Sys_pfs_max_stage_classes( "performance_schema_max_stage_classes", "Maximum number of stage instruments.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_stage_class_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256), - DEFAULT(PFS_MAX_STAGE_CLASS), - BLOCK_SIZE(1)); + DEFAULT(PFS_MAX_STAGE_CLASS), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_stages_history_long_size( "performance_schema_events_stages_history_long_size", @@ -275,8 +296,7 @@ static Sys_var_long Sys_pfs_events_stages_history_long_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_long_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_stages_history_size( "performance_schema_events_stages_history_size", @@ -284,26 +304,27 @@ static Sys_var_long Sys_pfs_events_stages_history_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); /** Variable performance_schema_max_statement_classes. The default number of statement classes is the sum of: + - SQLCOM_END for all regular "statement/sql/...", + - SP_PSI_STATEMENT_INFO_COUNT for "statement/sp/...". - (COM_END - mariadb gap) for all regular "statement/com/...", - 1 for "statement/com/new_packet", for unknown enum_server_command - 1 for "statement/com/Error", for invalid enum_server_command - - SQLCOM_END for all regular "statement/sql/...", - 1 for "statement/sql/error", for invalid enum_sql_command - 1 for "statement/rpl/relay_log", for replicated statements. + - 1 for "statement/scheduler/event", for scheduled events. */ static Sys_var_ulong Sys_pfs_max_statement_classes( "performance_schema_max_statement_classes", "Maximum number of statement instruments.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256), - DEFAULT((ulong) SQLCOM_END + - (ulong) (COM_END -(COM_MDB_GAP_END - COM_MDB_GAP_BEG + 1)) + 4), + DEFAULT((ulong) SQLCOM_END + SP_PSI_STATEMENT_INFO_COUNT + + (ulong) (COM_END -(COM_MDB_GAP_END - COM_MDB_GAP_BEG + 1)) + 5), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_statements_history_long_size( @@ -312,8 +333,7 @@ static Sys_var_long Sys_pfs_events_statements_history_long_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_long_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_statements_history_size( "performance_schema_events_statements_history_size", @@ -321,8 +341,21 @@ static Sys_var_long Sys_pfs_events_statements_history_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_statement_stack_size( + "performance_schema_max_statement_stack", + "Number of rows per thread in EVENTS_STATEMENTS_CURRENT.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_stack_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(1, 256), + DEFAULT(PFS_STATEMENTS_STACK_SIZE), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_max_memory_classes( + "performance_schema_max_memory_classes", + "Maximum number of memory pool instruments.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_memory_class_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024), + DEFAULT(PFS_MAX_MEMORY_CLASS), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_digest_size( "performance_schema_digests_size", @@ -330,16 +363,30 @@ static Sys_var_long Sys_pfs_digest_size( " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 200), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_events_transactions_history_long_size( + "performance_schema_events_transactions_history_long_size", + "Number of rows in EVENTS_TRANSACTIONS_HISTORY_LONG." + " Use 0 to disable, -1 for automated sizing.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_transactions_history_long_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), + DEFAULT(PFS_AUTOSIZE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_events_transactions_history_size( + "performance_schema_events_transactions_history_size", + "Number of rows per thread in EVENTS_TRANSACTIONS_HISTORY." + " Use 0 to disable, -1 for automated sizing.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_transactions_history_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024), + DEFAULT(PFS_AUTOSIZE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_max_digest_length( "performance_schema_max_digest_length", "Maximum length considered for digest text, when stored in performance_schema tables.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_max_digest_length), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024 * 1024), - DEFAULT(1024), - BLOCK_SIZE(1)); + DEFAULT(1024), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_connect_attrs_size( "performance_schema_session_connect_attrs_size", @@ -348,8 +395,22 @@ static Sys_var_long Sys_pfs_connect_attrs_size( PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_session_connect_attrs_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024 * 1024), - DEFAULT(-1), - BLOCK_SIZE(1)); + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_metadata_locks( + "performance_schema_max_metadata_locks", + "Maximum number of metadata locks." + " Use 0 to disable, -1 for automated scaling.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_metadata_lock_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024), + DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); + +static Sys_var_long Sys_pfs_max_sql_text_length( + "performance_schema_max_sql_text_length", + "Maximum length of displayed sql text.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_max_sql_text_length), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024 * 1024), + DEFAULT(1024), BLOCK_SIZE(1)); #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ @@ -523,7 +584,8 @@ bool check_has_super(sys_var *self, THD *thd, set_var *var) { DBUG_ASSERT(self->scope() != sys_var::GLOBAL);// don't abuse check_has_super() #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!(thd->security_ctx->master_access & SUPER_ACL)) + if (!(thd->security_ctx->master_access & + PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE)) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); return true; @@ -1517,24 +1579,21 @@ static Sys_var_ulong Sys_slave_max_allowed_packet( "The maximum packet length to sent successfully from the master to slave.", GLOBAL_VAR(slave_max_allowed_packet), CMD_LINE(REQUIRED_ARG), VALID_RANGE(1024, MAX_MAX_ALLOWED_PACKET), - DEFAULT(MAX_MAX_ALLOWED_PACKET), - BLOCK_SIZE(1024)); + DEFAULT(MAX_MAX_ALLOWED_PACKET), BLOCK_SIZE(1024)); static Sys_var_ulonglong Sys_max_binlog_cache_size( "max_binlog_cache_size", "Sets the total size of the transactional cache", GLOBAL_VAR(max_binlog_cache_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(IO_SIZE, SIZE_T_MAX), - DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), - BLOCK_SIZE(IO_SIZE)); + DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), BLOCK_SIZE(IO_SIZE)); static Sys_var_ulonglong Sys_max_binlog_stmt_cache_size( "max_binlog_stmt_cache_size", "Sets the total size of the statement cache", GLOBAL_VAR(max_binlog_stmt_cache_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(IO_SIZE, SIZE_T_MAX), - DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), - BLOCK_SIZE(IO_SIZE)); + DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), BLOCK_SIZE(IO_SIZE)); static bool fix_max_binlog_size(sys_var *self, THD *thd, enum_var_type type) { @@ -1935,7 +1994,8 @@ Sys_var_gtid_binlog_state::do_check(THD *thd, set_var *var) my_error(ER_INCORRECT_GTID_STATE, MYF(0)); return true; } - if (!(data= (gtid_binlog_state_data *)my_malloc(sizeof(*data), MYF(0)))) + if (!(data= (gtid_binlog_state_data *)my_malloc(PSI_INSTRUMENT_ME, + sizeof(*data), MYF(0)))) { my_free(list); my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -3136,16 +3196,17 @@ static Sys_var_enum Slave_ddl_exec_mode( slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_IDEMPOTENT)); static const char *slave_run_triggers_for_rbr_names[]= - {"NO", "YES", "LOGGING", 0}; + {"NO", "YES", "LOGGING", "ENFORCE", 0}; static Sys_var_enum Slave_run_triggers_for_rbr( "slave_run_triggers_for_rbr", "Modes for how triggers in row-base replication on slave side will be " - "executed. Legal values are NO (default), YES and LOGGING. NO means " + "executed. Legal values are NO (default), YES, LOGGING and ENFORCE. NO means " "that trigger for RBR will not be running on slave. YES and LOGGING " "means that triggers will be running on slave, if there was not " "triggers running on the master for the statement. LOGGING also means " "results of that the executed triggers work will be written to " - "the binlog.", + "the binlog. ENFORCE means that triggers will always be run on the slave, " + "even if there are triggers on the master. ENFORCE implies LOGGING.", GLOBAL_VAR(slave_run_triggers_for_rbr), CMD_LINE(REQUIRED_ARG), slave_run_triggers_for_rbr_names, DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO)); @@ -3901,8 +3962,7 @@ static Sys_var_ulonglong Sys_tmp_disk_table_size( "Max size for data for an internal temporary on-disk MyISAM or Aria table.", SESSION_VAR(tmp_disk_table_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(1024, (ulonglong)~(intptr)0), - DEFAULT((ulonglong)~(intptr)0), - BLOCK_SIZE(1)); + DEFAULT((ulonglong)~(intptr)0), BLOCK_SIZE(1)); static Sys_var_charptr Sys_version( "version", "Server version number. It may also include a suffix " @@ -4009,7 +4069,8 @@ static Sys_var_plugin Sys_enforce_storage_engine( "enforce_storage_engine", "Force the use of a storage engine for new tables", SESSION_VAR(enforced_table_plugin), NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN, - DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); + DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(check_has_super)); #ifdef HAVE_REPLICATION @@ -4189,7 +4250,8 @@ static Sys_var_bit Sys_log_off( "query log is done for the client. Only clients with the SUPER privilege " "can update this variable.", NO_SET_STMT SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF, - DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); + DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(check_has_super)); /** This function sets the session variable thd->variables.sql_log_bin @@ -5846,8 +5908,7 @@ static Sys_var_ulong Sys_host_cache_size( "How many host names should be cached to avoid resolving.", AUTO_SET GLOBAL_VAR(host_cache_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 65536), - DEFAULT(HOST_CACHE_SIZE), - BLOCK_SIZE(1), + DEFAULT(HOST_CACHE_SIZE), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_host_cache_size)); @@ -6334,8 +6395,7 @@ static Sys_var_ulong Sys_log_tc_size( READ_ONLY GLOBAL_VAR(opt_tc_log_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(my_getpagesize() * 3, ULONG_MAX), - DEFAULT(my_getpagesize() * 6), - BLOCK_SIZE(my_getpagesize())); + DEFAULT(my_getpagesize() * 6), BLOCK_SIZE(my_getpagesize())); #endif static Sys_var_ulonglong Sys_max_thread_mem( diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index f33f469b160..698062d9bed 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -529,7 +529,8 @@ public: size_t len=var->save_result.string_value.length; if (ptr) { - new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME)); + new_val= (char*)my_memdup(key_memory_Sys_var_charptr_value, + ptr, len+1, MYF(MY_WME)); if (!new_val) return 0; new_val[len]=0; } diff --git a/sql/table.cc b/sql/table.cc index 718efa5767c..10c44013538 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -27,7 +27,6 @@ #include "strfunc.h" // unhex_type2 #include "sql_partition.h" // mysql_unpack_partition, // fix_partition_func, partition_info -#include "sql_acl.h" // *_ACL, acl_getroot_no_password #include "sql_base.h" #include "create_options.h" #include "sql_trigger.h" @@ -273,7 +272,7 @@ TABLE_CATEGORY get_table_category(const LEX_CSTRING *db, if (is_infoschema_db(db)) return TABLE_CATEGORY_INFORMATION; - if (lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, db)) + if (is_perfschema_db(db)) return TABLE_CATEGORY_PERFORMANCE; if (lex_string_eq(&MYSQL_SCHEMA_NAME, db)) @@ -323,7 +322,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, path_length= build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0); - init_sql_alloc(&mem_root, "table_share", TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_table_share, &mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, + MYF(0)); if (multi_alloc_root(&mem_root, &share, sizeof(*share), &key_buff, key_length, @@ -349,7 +349,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, table_alias_charset->strnncoll(key, 6, "mysql", 6) == 0) share->not_usable_by_query_cache= 1; - init_sql_alloc(&share->stats_cb.mem_root, "share_stats", + init_sql_alloc(PSI_INSTRUMENT_ME, &share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0)); memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root)); @@ -411,8 +411,9 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, This can't be MY_THREAD_SPECIFIC for slaves as they are freed during cleanup() from Relay_log_info::close_temporary_tables() */ - init_sql_alloc(&share->mem_root, "tmp_table_share", TABLE_ALLOC_BLOCK_SIZE, - 0, MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC)); + init_sql_alloc(key_memory_table_share, &share->mem_root, + TABLE_ALLOC_BLOCK_SIZE, 0, + MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC)); share->table_category= TABLE_CATEGORY_TEMPORARY; share->tmp_table= INTERNAL_TMP_TABLE; share->db.str= (char*) key; @@ -676,7 +677,8 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) frmlen= uint4korr(head+10); set_if_smaller(frmlen, FRM_MAX_SIZE); // safety - if (!(buf= (uchar*)my_malloc(frmlen, MYF(MY_THREAD_SPECIFIC|MY_WME)))) + if (!(buf= (uchar*)my_malloc(PSI_INSTRUMENT_ME, frmlen, + MYF(MY_THREAD_SPECIFIC|MY_WME)))) goto err; memcpy(buf, head, sizeof(head)); @@ -2195,10 +2197,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH; if (use_hash) - use_hash= !my_hash_init(&share->name_hash, - system_charset_info, - share->fields,0,0, - (my_hash_get_key) get_field_name,0,0); + use_hash= !my_hash_init(PSI_INSTRUMENT_ME, &share->name_hash, + system_charset_info, share->fields, 0, 0, + (my_hash_get_key) get_field_name, 0, 0); if (share->mysql_version >= 50700 && share->mysql_version < 100000 && vcol_screen_length) @@ -3756,8 +3757,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, error= OPEN_FRM_NEEDS_REBUILD; goto err; } - init_sql_alloc(&outparam->mem_root, "table", TABLE_ALLOC_BLOCK_SIZE, 0, - MYF(0)); + init_sql_alloc(key_memory_TABLE, &outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, + 0, MYF(0)); /* We have to store the original alias in mem_root as constraints and virtual @@ -6207,7 +6208,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd) } else { - if (thd->security_ctx->master_access & SUPER_ACL) + if (thd->security_ctx->master_access & PRIV_REVEAL_MISSING_DEFINER) { my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str); @@ -8219,11 +8220,10 @@ size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data) void init_mdl_requests(TABLE_LIST *table_list) { for ( ; table_list ; table_list= table_list->next_global) - table_list->mdl_request.init(MDL_key::TABLE, - table_list->db.str, table_list->table_name.str, - table_list->lock_type >= TL_WRITE_ALLOW_WRITE ? - MDL_SHARED_WRITE : MDL_SHARED_READ, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE, + table_list->db.str, table_list->table_name.str, + table_list->lock_type >= TL_WRITE_ALLOW_WRITE + ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION); } diff --git a/sql/table.h b/sql/table.h index 6ce92ee048e..ad3336b9bd9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1075,8 +1075,8 @@ private: public: Blob_mem_storage() :truncated_value(false) { - init_alloc_root(&storage, "Blob_mem_storage", MAX_FIELD_VARCHARLENGTH, 0, - MYF(0)); + init_alloc_root(key_memory_blob_mem_storage, + &storage, MAX_FIELD_VARCHARLENGTH, 0, MYF(0)); } ~ Blob_mem_storage() { @@ -2012,8 +2012,8 @@ struct TABLE_LIST alias= (alias_arg ? *alias_arg : *table_name_arg); lock_type= lock_type_arg; updating= lock_type >= TL_WRITE_ALLOW_WRITE; - mdl_request.init(MDL_key::TABLE, db.str, table_name.str, mdl_type, - MDL_TRANSACTION); + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, db.str, table_name.str, + mdl_type, MDL_TRANSACTION); } TABLE_LIST(TABLE *table_arg, thr_lock_type lock_type) @@ -3060,9 +3060,12 @@ extern LEX_CSTRING MYSQL_PROC_NAME; inline bool is_infoschema_db(const LEX_CSTRING *name) { - return (INFORMATION_SCHEMA_NAME.length == name->length && - !my_strcasecmp(system_charset_info, - INFORMATION_SCHEMA_NAME.str, name->str)); + return lex_string_eq(&INFORMATION_SCHEMA_NAME, name); +} + +inline bool is_perfschema_db(const LEX_CSTRING *name) +{ + return lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, name); } inline void mark_as_null_row(TABLE *table) diff --git a/sql/table_cache.cc b/sql/table_cache.cc index 8e5c3a8471d..d8786f72244 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -1257,10 +1257,10 @@ int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument, if (no_dups) { - init_alloc_root(&no_dups_argument.root, "no_dups", 4096, 4096, - MYF(alloc_flags)); - my_hash_init(&no_dups_argument.hash, &my_charset_bin, tdc_records(), 0, 0, - eliminate_duplicates_get_key, 0, hash_flags); + init_alloc_root(PSI_INSTRUMENT_ME, &no_dups_argument.root, 4096, 4096, MYF(alloc_flags)); + my_hash_init(PSI_INSTRUMENT_ME, &no_dups_argument.hash, &my_charset_bin, + tdc_records(), 0, 0, eliminate_duplicates_get_key, 0, + hash_flags); no_dups_argument.action= action; no_dups_argument.argument= argument; action= (my_hash_walk_action) eliminate_duplicates; diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 2e0f0a4918e..c675b11741a 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -955,7 +955,8 @@ TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm, /* Create the table definition key for the temporary table. */ key_length= create_tmp_table_def_key(key_cache, db, table_name); - if (!(share= (TMP_TABLE_SHARE *) my_malloc(sizeof(TMP_TABLE_SHARE) + + if (!(share= (TMP_TABLE_SHARE *) my_malloc(key_memory_table_share, + sizeof(TMP_TABLE_SHARE) + strlen(path) + 1 + key_length, MYF(MY_WME)))) { @@ -1002,7 +1003,8 @@ TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm, if (!temporary_tables) { if ((temporary_tables= - (All_tmp_tables_list *) my_malloc(sizeof(All_tmp_tables_list), + (All_tmp_tables_list *) my_malloc(key_memory_table_share, + sizeof(All_tmp_tables_list), MYF(MY_WME)))) { temporary_tables->empty(); @@ -1107,7 +1109,8 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, DBUG_ENTER("THD::open_temporary_table"); - if (!(table= (TABLE *) my_malloc(sizeof(TABLE), MYF(MY_WME)))) + if (!(table= (TABLE *) my_malloc(key_memory_TABLE, sizeof(TABLE), + MYF(MY_WME)))) { DBUG_RETURN(NULL); /* Out of memory */ } diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index d43e7c4c9b5..89ad359befa 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -58,11 +58,10 @@ extern "C" { } } -void init_sql_alloc(MEM_ROOT *mem_root, - const char *area_name __attribute__((unused)), - uint block_size, uint pre_alloc, myf my_flags) +void init_sql_alloc(PSI_memory_key key, MEM_ROOT *mem_root, uint block_size, + uint pre_alloc, myf my_flags) { - init_alloc_root(mem_root, area_name, block_size, pre_alloc, my_flags); + init_alloc_root(key, mem_root, block_size, pre_alloc, my_flags); mem_root->error_handler=sql_alloc_error_handler; } diff --git a/sql/thr_malloc.h b/sql/thr_malloc.h index a6ab5477d41..cc56666bcc9 100644 --- a/sql/thr_malloc.h +++ b/sql/thr_malloc.h @@ -18,8 +18,8 @@ typedef struct st_mem_root MEM_ROOT; -void init_sql_alloc(MEM_ROOT *root, const char *area_name, uint block_size, - uint pre_alloc_size, myf my_flags); +void init_sql_alloc(PSI_memory_key key, MEM_ROOT *root, uint block_size, uint + pre_alloc_size, myf my_flags); char *sql_strmake_with_convert(THD *thd, const char *str, size_t arg_length, CHARSET_INFO *from_cs, size_t max_res_length, diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 0588562ae61..40b230e5392 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -151,7 +151,7 @@ static void thread_attach(THD* thd) pthread_setspecific(THR_KEY_mysys,thd->mysys_var); thd->thread_stack=(char*)&thd; thd->store_globals(); - PSI_CALL_set_thread(thd->event_scheduler.m_psi); + PSI_CALL_set_thread(thd->get_psi()); mysql_socket_set_thread_owner(thd->net.vio->mysql_socket); } @@ -235,21 +235,13 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) pthread_setspecific(THR_KEY_mysys, 0); my_thread_init(); st_my_thread_var* mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys); + PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, connect, 0)); if (!mysys_var ||!(thd= connect->create_thd(NULL))) { /* Out of memory? */ connect->close_and_delete(); if (mysys_var) - { -#ifdef HAVE_PSI_INTERFACE - /* - current PSI is still from worker thread. - Set to 0, to avoid premature cleanup by my_thread_end - */ - if (PSI_server) PSI_server->set_thread(0); -#endif my_thread_end(); - } return NULL; } delete connect; @@ -257,11 +249,6 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) thd->set_mysys_var(mysys_var); thd->event_scheduler.data= scheduler_data; - /* Create new PSI thread for use with the THD. */ - thd->event_scheduler.m_psi= - PSI_CALL_new_thread(key_thread_one_connection, thd, thd->thread_id); - - /* Login. */ thread_attach(thd); re_init_net_server_extension(thd); @@ -301,6 +288,7 @@ static void threadpool_remove_connection(THD *thd) end_connection(thd); close_connection(thd, 0); unlink_thd(thd); + PSI_CALL_delete_current_thread(); // before THD is destroyed delete thd; /* diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index e11a0613425..e8e3497eae4 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1532,7 +1532,8 @@ int TP_pool_generic::init() DBUG_ENTER("TP_pool_generic::TP_pool_generic"); threadpool_max_size= MY_MAX(threadpool_size, 128); all_groups= (thread_group_t *) - my_malloc(sizeof(thread_group_t) * threadpool_max_size, MYF(MY_WME|MY_ZEROFILL)); + my_malloc(PSI_INSTRUMENT_ME, + sizeof(thread_group_t) * threadpool_max_size, MYF(MY_WME|MY_ZEROFILL)); if (!all_groups) { threadpool_max_size= 0; diff --git a/sql/transaction.cc b/sql/transaction.cc index f0426b1fcc4..82e04d35479 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -25,6 +25,8 @@ #include "debug_sync.h" // DEBUG_SYNC #include "sql_acl.h" #include "semisync_master.h" +#include <pfs_transaction_provider.h> +#include <mysql/psi/mysql_transaction.h> #ifdef WITH_WSREP #include "wsrep_trans_observer.h" #endif /* WITH_WSREP */ @@ -161,7 +163,7 @@ bool trans_begin(THD *thd, uint flags) compatibility. */ const bool user_is_super= - MY_TEST(thd->security_ctx->master_access & SUPER_ACL); + MY_TEST(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY); if (opt_readonly && !user_is_super) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); @@ -209,6 +211,23 @@ bool trans_begin(THD *thd, uint flags) #endif //EMBEDDED_LIBRARY res= ha_start_consistent_snapshot(thd); } + /* + Register transaction start in performance schema if not done already. + We handle explicitly started transactions here, implicitly started + transactions (and single-statement transactions in autocommit=1 mode) + are handled in trans_register_ha(). + We can't handle explicit transactions in the same way as implicit + because we want to correctly attribute statements which follow + BEGIN but do not touch any transactional tables. + */ + if (thd->m_transaction_psi == NULL) + { + thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state, + NULL, 0, thd->tx_isolation, + thd->tx_read_only, false); + DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid"); + //gtid_set_performance_schema_values(thd); + } DBUG_RETURN(MY_TEST(res)); } @@ -245,22 +264,18 @@ bool trans_commit(THD *thd) if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. */ - if (res) - { #ifdef HAVE_REPLICATION + if (res) repl_semisync_master.wait_after_rollback(thd, FALSE); -#endif - } else - { -#ifdef HAVE_REPLICATION repl_semisync_master.wait_after_commit(thd, FALSE); #endif - } thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.reset(); thd->lex->start_transaction_opt= 0; + /* The transaction should be marked as complete in P_S. */ + DBUG_ASSERT(thd->m_transaction_psi == NULL); trans_track_end_trx(thd); DBUG_RETURN(MY_TEST(res)); @@ -305,6 +320,9 @@ bool trans_commit_implicit(THD *thd) thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.reset(); + /* The transaction should be marked as complete in P_S. */ + DBUG_ASSERT(thd->m_transaction_psi == NULL); + /* Upon implicit commit, reset the current transaction isolation level and access mode. We do not care about @@ -349,6 +367,9 @@ bool trans_rollback(THD *thd) thd->transaction.all.reset(); thd->lex->start_transaction_opt= 0; + /* The transaction should be marked as complete in P_S. */ + DBUG_ASSERT(thd->m_transaction_psi == NULL); + trans_track_end_trx(thd); DBUG_RETURN(MY_TEST(res)); @@ -395,7 +416,9 @@ bool trans_rollback_implicit(THD *thd) thd->transaction.all.reset(); /* Rollback should clear transaction_rollback_request flag. */ - DBUG_ASSERT(! thd->transaction_rollback_request); + DBUG_ASSERT(!thd->transaction_rollback_request); + /* The transaction should be marked as complete in P_S. */ + DBUG_ASSERT(thd->m_transaction_psi == NULL); trans_track_end_trx(thd); @@ -463,6 +486,10 @@ bool trans_commit_stmt(THD *thd) #endif } + /* In autocommit=1 mode the transaction should be marked as complete in P_S */ + DBUG_ASSERT(thd->in_active_multi_stmt_transaction() || + thd->m_transaction_psi == NULL); + thd->transaction.stmt.reset(); DBUG_RETURN(MY_TEST(res)); @@ -502,6 +529,10 @@ bool trans_rollback_stmt(THD *thd) repl_semisync_master.wait_after_rollback(thd, FALSE); #endif + /* In autocommit=1 mode the transaction should be marked as complete in P_S */ + DBUG_ASSERT(thd->in_active_multi_stmt_transaction() || + thd->m_transaction_psi == NULL); + thd->transaction.stmt.reset(); DBUG_RETURN(FALSE); diff --git a/sql/tztime.cc b/sql/tztime.cc index fbac2923a84..72db37fde9c 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1543,6 +1543,8 @@ tz_init_table_list(TABLE_LIST *tz_tabs) } } +static PSI_memory_key key_memory_tz_storage; + #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_tz_LOCK; @@ -1551,6 +1553,11 @@ static PSI_mutex_info all_tz_mutexes[]= { & key_tz_LOCK, "tz_LOCK", PSI_FLAG_GLOBAL} }; +static PSI_memory_info all_tz_memory[]= +{ + { &key_memory_tz_storage, "tz_storage", PSI_FLAG_GLOBAL} +}; + static void init_tz_psi_keys(void) { const char* category= "sql"; @@ -1561,6 +1568,9 @@ static void init_tz_psi_keys(void) count= array_elements(all_tz_mutexes); PSI_server->register_mutex(category, all_tz_mutexes, count); + + count= array_elements(all_tz_memory); + mysql_memory_register(category, all_tz_memory, count); } #endif /* HAVE_PSI_INTERFACE */ @@ -1615,20 +1625,20 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) thd->store_globals(); /* Init all memory structures that require explicit destruction */ - if (my_hash_init(&tz_names, &my_charset_latin1, 20, - 0, 0, (my_hash_get_key) my_tz_names_get_key, 0, 0)) + if (my_hash_init(key_memory_tz_storage, &tz_names, &my_charset_latin1, 20, 0, + 0, (my_hash_get_key) my_tz_names_get_key, 0, 0)) { sql_print_error("Fatal error: OOM while initializing time zones"); goto end; } - if (my_hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0, - (my_hash_get_key)my_offset_tzs_get_key, 0, 0)) + if (my_hash_init(key_memory_tz_storage, &offset_tzs, &my_charset_latin1, 26, + 0, 0, (my_hash_get_key)my_offset_tzs_get_key, 0, 0)) { sql_print_error("Fatal error: OOM while initializing time zones"); my_hash_free(&tz_names); goto end; } - init_sql_alloc(&tz_storage, "timezone_storage", 32 * 1024, 0, MYF(0)); + init_sql_alloc(key_memory_tz_storage, &tz_storage, 32 * 1024, 0, MYF(0)); mysql_mutex_init(key_tz_LOCK, &tz_LOCK, MY_MUTEX_INIT_FAST); tz_inited= 1; @@ -2568,8 +2578,8 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level, uint verbose) } else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode)) { - init_alloc_root(&tz_storage, "timezone_storage", 32768, 0, - MYF(MY_THREAD_SPECIFIC)); + init_alloc_root(PSI_INSTRUMENT_ME, &tz_storage, + 32768, 0, MYF(MY_THREAD_SPECIFIC)); if (!tz_load(fullname, &tz_info, &tz_storage)) print_tz_as_sql(root_name_end + 1, &tz_info); else @@ -2758,7 +2768,7 @@ main(int argc, char **argv) First argument is timezonefile. The second is timezonename if opt_leap is not given */ - init_alloc_root(&tz_storage, "timezone_storage", 32768, 0, MYF(0)); + init_alloc_root(PSI_INSTRUMENT_ME, &tz_storage, 32768, 0, MYF(0)); if (tz_load(argv[0], &tz_info, &tz_storage)) { diff --git a/sql/uniques.cc b/sql/uniques.cc index 931aa868199..4e327a4cc09 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -93,8 +93,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, init_tree(&tree, (max_in_memory_size / 16), 0, size, comp_func, NULL, comp_func_fixed_arg, MYF(MY_THREAD_SPECIFIC)); /* If the following fail's the next add will also fail */ - my_init_dynamic_array(&file_ptrs, sizeof(Merge_chunk), 16, 16, - MYF(MY_THREAD_SPECIFIC)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &file_ptrs, sizeof(Merge_chunk), 16, + 16, MYF(MY_THREAD_SPECIFIC)); /* If you change the following, change it in get_max_elements function, too. */ @@ -531,7 +531,7 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size, top->set_buffer(merge_buffer + (top - begin) * piece_size, merge_buffer + (top - begin) * piece_size + piece_size); top->set_max_keys(max_key_count_per_piece); - bytes_read= read_to_buffer(file, top, &sort_param); + bytes_read= read_to_buffer(file, top, &sort_param, false); if (unlikely(bytes_read == (ulong) -1)) goto end; DBUG_ASSERT(bytes_read); @@ -561,7 +561,7 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size, /* save old_key not to overwrite it in read_to_buffer */ memcpy(save_key_buff, old_key, key_length); old_key= save_key_buff; - bytes_read= read_to_buffer(file, top, &sort_param); + bytes_read= read_to_buffer(file, top, &sort_param, false); if (unlikely(bytes_read == (ulong) -1)) goto end; else if (bytes_read) /* top->key, top->mem_count are reset */ @@ -609,7 +609,7 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size, top->advance_current_key(key_length); } while (top->decrement_mem_count()); - bytes_read= read_to_buffer(file, top, &sort_param); + bytes_read= read_to_buffer(file, top, &sort_param, false); if (unlikely(bytes_read == (ulong) -1)) goto end; } @@ -662,7 +662,8 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg) is needed when a piece of merge buffer is re-read, see merge_walk() */ size_t buff_sz= MY_MAX(MERGEBUFF2+1, max_in_memory_size/full_size+1) * full_size; - if (!(merge_buffer = (uchar *)my_malloc(buff_sz, MYF(MY_WME)))) + if (!(merge_buffer = (uchar *)my_malloc(key_memory_Unique_merge_buffer, + buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME)))) return 1; if (buff_sz < full_size * (file_ptrs.elements + 1UL)) res= merge(table, merge_buffer, buff_sz, @@ -782,7 +783,8 @@ bool Unique::get(TABLE *table) { /* Whole tree is in memory; Don't use disk if you don't need to */ if ((sort.record_pointers= (uchar*) - my_malloc(size * tree.elements_in_tree, MYF(MY_THREAD_SPECIFIC)))) + my_malloc(key_memory_Filesort_info_record_pointers, + size * tree.elements_in_tree, MYF(MY_THREAD_SPECIFIC)))) { uchar *save_record_pointers= sort.record_pointers; tree_walk_action action= min_dupl_count ? @@ -801,7 +803,7 @@ bool Unique::get(TABLE *table) if (flush()) DBUG_RETURN(1); size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size; - if (!(sort_buffer= (uchar*) my_malloc(buff_sz, + if (!(sort_buffer= (uchar*) my_malloc(key_memory_Unique_sort_buffer, buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME)))) DBUG_RETURN(1); diff --git a/sql/unireg.cc b/sql/unireg.cc index e4a43d3ace5..2aa46131efb 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -425,8 +425,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table, DBUG_RETURN(frm); } - frm_ptr= (uchar*) my_malloc(frm.length, MYF(MY_WME | MY_ZEROFILL | - MY_THREAD_SPECIFIC)); + frm_ptr= (uchar*) my_malloc(PSI_INSTRUMENT_ME, frm.length, + MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC)); if (!frm_ptr) DBUG_RETURN(frm); diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index a81503a50da..f555480d2e0 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -64,7 +64,7 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len) wsrep_max_ws_size, total_length); goto error; } - uchar* tmp= (uchar *)my_realloc(*buf, total_length, + uchar* tmp= (uchar *)my_realloc(PSI_INSTRUMENT_ME, *buf, total_length, MYF(MY_ALLOW_ZERO_PTR)); if (!tmp) { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index ff01473e816..99e8f0a52ec 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1270,7 +1270,7 @@ static bool wsrep_prepare_key_for_isolation(const char* db, wsrep_key_arr_t* ka) { wsrep_key_t* tmp; - tmp= (wsrep_key_t*)my_realloc(ka->keys, + tmp= (wsrep_key_t*)my_realloc(PSI_INSTRUMENT_ME, ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(MY_ALLOW_ZERO_PTR)); if (!tmp) @@ -1280,7 +1280,7 @@ static bool wsrep_prepare_key_for_isolation(const char* db, } ka->keys= tmp; if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*) - my_malloc(sizeof(wsrep_buf_t)*2, MYF(0)))) + my_malloc(PSI_INSTRUMENT_ME, sizeof(wsrep_buf_t)*2, MYF(0)))) { WSREP_ERROR("Can't allocate memory for key_parts"); return false; @@ -1916,7 +1916,7 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len) log_query.set_charset(system_charset_info); - if (sp->m_handler->type() == TYPE_ENUM_FUNCTION) + if (sp->m_handler->type() == SP_TYPE_FUNCTION) { sp_returns_type(thd, retstr, sp); returns= retstr.lex_cstring(); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index d478ea486cd..0bb8a9eb675 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -245,7 +245,7 @@ static bool sst_auth_real_set (const char* value) if (value) { - v= my_strdup(value, MYF(0)); + v= my_strdup(PSI_INSTRUMENT_ME, value, MYF(0)); } else // its NULL { @@ -263,7 +263,7 @@ static bool sst_auth_real_set (const char* value) if (strlen(sst_auth_real)) { if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); } - wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0)); + wsrep_sst_auth= my_strdup(PSI_INSTRUMENT_ME, WSREP_SST_AUTH_MASK, MYF(0)); } return 0; } @@ -414,7 +414,7 @@ static char* generate_name_value(const char* name, const char* value) size_t name_len= strlen(name); size_t value_len= strlen(value); char* buf= - (char*) my_malloc((name_len + value_len + 5) * sizeof(char), MYF(0)); + (char*) my_malloc(PSI_INSTRUMENT_ME, (name_len + value_len + 5), MYF(0)); if (buf) { char* ref= buf; @@ -449,11 +449,11 @@ static int generate_binlog_opt_val(char** ret) *ret= strcmp(opt_bin_logname, "0") ? generate_name_value(WSREP_SST_OPT_BINLOG, opt_bin_logname) : - my_strdup("", MYF(0)); + my_strdup(PSI_INSTRUMENT_ME, "", MYF(0)); } else { - *ret= my_strdup("", MYF(0)); + *ret= my_strdup(PSI_INSTRUMENT_ME, "", MYF(0)); } if (!*ret) return -ENOMEM; return 0; @@ -468,11 +468,11 @@ static int generate_binlog_index_opt_val(char** ret) *ret= strcmp(opt_binlog_index_name, "0") ? generate_name_value(WSREP_SST_OPT_BINLOG_INDEX, opt_binlog_index_name) : - my_strdup("", MYF(0)); + my_strdup(PSI_INSTRUMENT_ME, "", MYF(0)); } else { - *ret= my_strdup("", MYF(0)); + *ret= my_strdup(PSI_INSTRUMENT_ME, "", MYF(0)); } if (!*ret) return -ENOMEM; return 0; diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 950e4aae34d..28dbe4096f7 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -30,17 +30,17 @@ ulong wsrep_reject_queries; int wsrep_init_vars() { - wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME)); - wsrep_provider_options= my_strdup("", MYF(MY_WME)); - wsrep_cluster_address = my_strdup("", MYF(MY_WME)); - wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME)); - wsrep_node_name = my_strdup("", MYF(MY_WME)); - wsrep_node_address = my_strdup("", MYF(MY_WME)); - wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME)); + wsrep_provider = my_strdup(PSI_INSTRUMENT_ME, WSREP_NONE, MYF(MY_WME)); + wsrep_provider_options= my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME)); + wsrep_cluster_address = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME)); + wsrep_cluster_name = my_strdup(PSI_INSTRUMENT_ME, WSREP_CLUSTER_NAME, MYF(MY_WME)); + wsrep_node_name = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME)); + wsrep_node_address = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME)); + wsrep_node_incoming_address= my_strdup(PSI_INSTRUMENT_ME, WSREP_NODE_INCOMING_AUTO, MYF(MY_WME)); if (wsrep_gtid_mode) - wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO_GTID, MYF(MY_WME)); + wsrep_start_position = my_strdup(PSI_INSTRUMENT_ME, WSREP_START_POSITION_ZERO_GTID, MYF(MY_WME)); else - wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME)); + wsrep_start_position = my_strdup(PSI_INSTRUMENT_ME, WSREP_START_POSITION_ZERO, MYF(MY_WME)); return 0; } @@ -50,7 +50,7 @@ static int get_provider_option_value(const char* opts, { int ret= 1; ulong opt_value_tmp; - char *opt_value_str, *s, *opts_copy= my_strdup(opts, MYF(MY_WME)); + char *opt_value_str, *s, *opts_copy= my_strdup(PSI_INSTRUMENT_ME, opts, MYF(MY_WME)); if ((opt_value_str= strstr(opts_copy, opt_name)) == NULL) goto end; @@ -436,7 +436,7 @@ void wsrep_provider_init (const char* value) } if (wsrep_provider) my_free((void *)wsrep_provider); - wsrep_provider= my_strdup(value, MYF(0)); + wsrep_provider= my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)); } bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) @@ -466,7 +466,7 @@ void wsrep_provider_options_init(const char* value) { if (wsrep_provider_options && wsrep_provider_options != value) my_free((void *)wsrep_provider_options); - wsrep_provider_options= (value) ? my_strdup(value, MYF(0)) : NULL; + wsrep_provider_options= value ? my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)) : NULL; } bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type) @@ -578,8 +578,8 @@ void wsrep_cluster_address_init (const char* value) (wsrep_cluster_address) ? wsrep_cluster_address : "null", (value) ? value : "null"); - my_free((void*) wsrep_cluster_address); - wsrep_cluster_address= my_strdup(value ? value : "", MYF(0)); + my_free(const_cast<char*>(wsrep_cluster_address)); + wsrep_cluster_address= my_strdup(PSI_INSTRUMENT_MEM, safe_str(value), MYF(0)); } /* wsrep_cluster_name cannot be NULL or an empty string. */ @@ -652,7 +652,7 @@ void wsrep_node_address_init (const char* value) if (wsrep_node_address && strcmp(wsrep_node_address, value)) my_free ((void*)wsrep_node_address); - wsrep_node_address= (value) ? my_strdup(value, MYF(0)) : NULL; + wsrep_node_address= value ? my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)) : NULL; } static void wsrep_slave_count_change_update () diff --git a/sql/xa.cc b/sql/xa.cc index 3ead73fe1e1..4d9846d2f4d 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -19,10 +19,11 @@ #include "mariadb.h" #include "sql_class.h" #include "transaction.h" - +#include <pfs_transaction_provider.h> +#include <mysql/psi/mysql_transaction.h> /*************************************************************************** - Handling of XA id cacheing + Handling of XA id caching ***************************************************************************/ enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY }; @@ -425,19 +426,25 @@ bool trans_xa_start(THD *thd) if (not_equal) my_error(ER_XAER_NOTA, MYF(0)); else + { thd->transaction.xid_state.xid_cache_element->xa_state= XA_ACTIVE; + MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_ACTIVE); + } DBUG_RETURN(not_equal); } /* TODO: JOIN is not supported yet. */ if (thd->lex->xa_opt != XA_NONE) my_error(ER_XAER_INVAL, MYF(0)); + else if (!thd->lex->xid->gtrid_length) + my_error(ER_XAER_INVAL, MYF(0)); else if (thd->transaction.xid_state.is_explicit_XA()) thd->transaction.xid_state.er_xaer_rmfail(); else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) my_error(ER_XAER_OUTSIDE, MYF(0)); else if (!trans_begin(thd)) { + MYSQL_SET_TRANSACTION_XID(thd->m_transaction_psi, thd->lex->xid, XA_ACTIVE); if (xid_cache_insert(thd, &thd->transaction.xid_state, thd->lex->xid)) { trans_rollback(thd); @@ -472,7 +479,10 @@ bool trans_xa_end(THD *thd) else if (!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid)) my_error(ER_XAER_NOTA, MYF(0)); else if (!xa_trans_rolled_back(thd->transaction.xid_state.xid_cache_element)) + { thd->transaction.xid_state.xid_cache_element->xa_state= XA_IDLE; + MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_IDLE); + } DBUG_RETURN(thd->is_error() || thd->transaction.xid_state.xid_cache_element->xa_state != XA_IDLE); @@ -503,7 +513,10 @@ bool trans_xa_prepare(THD *thd) my_error(ER_XA_RBROLLBACK, MYF(0)); } else + { thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED; + MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_PREPARED); + } DBUG_RETURN(thd->is_error() || thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED); @@ -527,6 +540,24 @@ bool trans_xa_commit(THD *thd) if (!thd->transaction.xid_state.is_explicit_XA() || !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid)) { + if (thd->in_multi_stmt_transaction_mode()) + { + /* + Not allow to commit from inside an not-"native" to xid + ongoing transaction: the commit effect can't be reversed. + */ + my_error(ER_XAER_OUTSIDE, MYF(0)); + DBUG_RETURN(TRUE); + } + if (thd->lex->xa_opt != XA_NONE) + { + /* + Not allow to commit with one phase a prepared xa out of compatibility + with the native commit branch's error out. + */ + my_error(ER_XAER_INVAL, MYF(0)); + DBUG_RETURN(TRUE); + } if (thd->fix_xid_hash_pins()) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -556,10 +587,14 @@ bool trans_xa_commit(THD *thd) if ((res= MY_TEST(r))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); } - else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED && - thd->lex->xa_opt == XA_NONE) + else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED) { MDL_request mdl_request; + if (thd->lex->xa_opt != XA_NONE) + { + my_error(ER_XAER_INVAL, MYF(0)); + DBUG_RETURN(TRUE); + } /* Acquire metadata lock which will ensure that COMMIT is blocked @@ -568,7 +603,7 @@ bool trans_xa_commit(THD *thd) We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does. */ - mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_TRANSACTION); if (thd->mdl_context.acquire_lock(&mdl_request, @@ -584,6 +619,16 @@ bool trans_xa_commit(THD *thd) res= MY_TEST(ha_commit_one_phase(thd, 1)); if (res) my_error(ER_XAER_RMERR, MYF(0)); + else + { + /* + Since we don't call ha_commit_trans() for prepared transactions, + we need to explicitly mark the transaction as committed. + */ + MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); + } + + thd->m_transaction_psi= NULL; } } else @@ -600,7 +645,8 @@ bool trans_xa_commit(THD *thd) xid_cache_delete(thd, &thd->transaction.xid_state); trans_track_end_trx(thd); - + /* The transaction should be marked as complete in P_S. */ + DBUG_ASSERT(thd->m_transaction_psi == NULL || res); DBUG_RETURN(res); } @@ -621,6 +667,11 @@ bool trans_xa_rollback(THD *thd) if (!thd->transaction.xid_state.is_explicit_XA() || !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid)) { + if (thd->in_multi_stmt_transaction_mode()) + { + my_error(ER_XAER_OUTSIDE, MYF(0)); + DBUG_RETURN(TRUE); + } if (thd->fix_xid_hash_pins()) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); |