diff options
Diffstat (limited to 'sql')
87 files changed, 4402 insertions, 1617 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 4aa7b8f882e..8c2b6c81755 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -60,7 +60,8 @@ SET (SQL_SOURCE sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc - sql_list.cc sql_load.cc sql_manager.cc sql_parse.cc + sql_list.cc sql_load.cc sql_manager.cc + sql_parse.cc sql_bootstrap.cc sql_bootstrap.h sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc debug_sync.cc debug_sync.h sql_repl.cc sql_select.cc sql_show.cc sql_state.c @@ -77,7 +78,7 @@ SET (SQL_SOURCE sql_profile.cc event_parse_data.cc sql_alter.cc sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc transaction.cc sys_vars.cc sql_truncate.cc datadict.cc - sql_reload.cc + sql_reload.cc sql_cmd.h # added in MariaDB: sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 28d1109a0b4..25f028e5451 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1522,6 +1522,8 @@ static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) { if (!thd) thd= current_thd; + if (!thd) + return; st_debug_sync_control *ds_control= thd->debug_sync_control; st_debug_sync_action *action; diff --git a/sql/derror.cc b/sql/derror.cc index 33835992258..665427f45bc 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -186,12 +186,12 @@ bool read_texts(const char *file_name, const char *language, goto err; funktpos=2; if (head[0] != (uchar) 254 || head[1] != (uchar) 254 || - head[2] != 2 || head[3] != 1) + head[2] != 2 || head[3] != 2) goto err; /* purecov: inspected */ textcount=head[4]; error_message_charset_info= system_charset_info; - length=uint2korr(head+6); count=uint2korr(head+8); + length=uint4korr(head+6); count=uint2korr(head+10); if (count < error_messages) { @@ -203,7 +203,7 @@ Error message file '%s' had only %d error messages, but it should contain at lea } if (!(*point= (const char**) - my_malloc((size_t) (length+count*sizeof(char*)),MYF(0)))) + my_malloc((size_t) (max(length,count*2)+count*sizeof(char*)),MYF(0)))) { funktpos=3; /* purecov: inspected */ goto err; /* purecov: inspected */ diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 14b1003d308..2e31d20d54e 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1462,13 +1462,19 @@ end: NOTE: even if we run in read-only mode, we should be able to lock the mysql.event table for writing. In order to achieve this, we should call mysql_lock_tables() under the super-user. + + Same goes for transaction access mode. + Temporarily reset it to read-write. */ saved_master_access= thd->security_ctx->master_access; thd->security_ctx->master_access |= SUPER_ACL; + bool save_tx_read_only= thd->tx_read_only; + thd->tx_read_only= false; ret= Events::drop_event(thd, dbname, name, FALSE); + thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; } } diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index b7e82d8b4b9..9a943d8bb59 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -222,7 +222,8 @@ mysql_event_fill_row(THD *thd, Safety: this can only happen if someone started the server and then altered mysql.event. */ - my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, MYF(0), table->alias.c_ptr(), + my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, MYF(0), + table->s->db.str, table->alias.c_ptr(), (int) ET_FIELD_COUNT, table->s->fields); DBUG_RETURN(TRUE); } @@ -432,7 +433,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, key_info->key_part[0].field != event_table->field[ET_FIELD_DB]) { /* Corrupted table: no index or index on a wrong column */ - my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event"); + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event"); ret= 1; goto end; } @@ -1087,7 +1088,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, if ((ret= find_named_event(dbname, name, event_table.table))) my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str); else if ((ret= etn->load_from_row(thd, event_table.table))) - my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event"); + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event"); close_system_tables(thd, &open_tables_backup); } diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 40fddff094c..0324e05fb27 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -10,8 +10,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include "sql_priv.h" #include "unireg.h" @@ -559,9 +559,6 @@ Event_queue::dbug_dump_queue(my_time_t when) #endif } -static const char *queue_empty_msg= "Waiting on empty queue"; -static const char *queue_wait_msg= "Waiting for next activation"; - /* Checks whether the top of the queue is elligible for execution and returns an Event_job_data instance in case it should be executed. @@ -608,7 +605,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd, mysql_audit_release(thd); /* Wait on condition until signaled. Release LOCK_queue while waiting. */ - cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__); + cond_wait(thd, NULL, & stage_waiting_on_empty_queue, SCHED_FUNC, __FILE__, __LINE__); continue; } @@ -629,7 +626,8 @@ Event_queue::get_top_for_execution_if_time(THD *thd, /* Release any held audit resources before waiting */ mysql_audit_release(thd); - cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__); + cond_wait(thd, &top_time, &stage_waiting_for_next_activation, SCHED_FUNC, __FILE__, __LINE__); + continue; } @@ -759,16 +757,16 @@ Event_queue::unlock_data(const char *func, uint line) */ void -Event_queue::cond_wait(THD *thd, struct timespec *abstime, const char* msg, - const char *func, uint line) +Event_queue::cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, + const char *src_func, const char *src_file, uint src_line) { DBUG_ENTER("Event_queue::cond_wait"); waiting_on_cond= TRUE; - mutex_last_unlocked_at_line= line; + mutex_last_unlocked_at_line= src_line; mutex_queue_data_locked= FALSE; - mutex_last_unlocked_in_func= func; + mutex_last_unlocked_in_func= src_func; - thd->enter_cond(&COND_queue_state, &LOCK_event_queue, msg); + thd->enter_cond(&COND_queue_state, &LOCK_event_queue, stage, NULL, src_func, src_file, src_line); if (!thd->killed) { @@ -779,8 +777,8 @@ Event_queue::cond_wait(THD *thd, struct timespec *abstime, const char* msg, mysql_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime); } - mutex_last_locked_in_func= func; - mutex_last_locked_at_line= line; + mutex_last_locked_in_func= src_func; + mutex_last_locked_at_line= src_line; mutex_queue_data_locked= TRUE; waiting_on_cond= FALSE; @@ -788,8 +786,8 @@ Event_queue::cond_wait(THD *thd, struct timespec *abstime, const char* msg, This will free the lock so we need to relock. Not the best thing to do but we need to obey cond_wait() */ - thd->exit_cond(""); - lock_data(func, line); + thd->exit_cond(NULL, src_func, src_file, src_line); + lock_data(src_func, src_line); DBUG_VOID_RETURN; } diff --git a/sql/event_queue.h b/sql/event_queue.h index affa306b259..fdd5937ee17 100644 --- a/sql/event_queue.h +++ b/sql/event_queue.h @@ -12,8 +12,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /** @@ -94,8 +94,8 @@ private: unlock_data(const char *func, uint line); void - cond_wait(THD *thd, struct timespec *abstime, const char* msg, - const char *func, uint line); + cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, + const char *src_func, const char *src_file, uint src_line); void find_n_remove_event(LEX_STRING db, LEX_STRING name); diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 8c3e57778ab..ec96ca45a0e 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -38,8 +38,8 @@ #define LOCK_DATA() lock_data(SCHED_FUNC, __LINE__) #define UNLOCK_DATA() unlock_data(SCHED_FUNC, __LINE__) -#define COND_STATE_WAIT(mythd, abstime, msg) \ - cond_wait(mythd, abstime, msg, SCHED_FUNC, __LINE__) +#define COND_STATE_WAIT(mythd, abstime, stage) \ + cond_wait(mythd, abstime, stage, SCHED_FUNC, __FILE__, __LINE__) extern pthread_attr_t connection_attrib; extern ulong event_executed; @@ -407,14 +407,18 @@ Event_scheduler::start() pre_init_event_thread(new_thd); new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER; - new_thd->command= COM_DAEMON; + new_thd->set_command(COM_DAEMON); /* We should run the event scheduler thread under the super-user privileges. In particular, this is needed to be able to lock the mysql.event table for writing when the server is running in the read-only mode. + + Same goes for transaction access mode. Set it to read-write for this thd. */ new_thd->security_ctx->master_access |= SUPER_ACL; + 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= @@ -631,7 +635,7 @@ Event_scheduler::stop() { /* Synchronously wait until the scheduler stops. */ while (state != INITIALIZED) - COND_STATE_WAIT(thd, NULL, "Waiting for the scheduler to stop"); + COND_STATE_WAIT(thd, NULL, &stage_waiting_for_scheduler_to_stop); goto end; } @@ -673,7 +677,7 @@ Event_scheduler::stop() */ struct timespec top_time; set_timespec(top_time, 2); - COND_STATE_WAIT(thd, &top_time, "Waiting scheduler to stop"); + COND_STATE_WAIT(thd, &top_time, &stage_waiting_for_scheduler_to_stop); } while (state == STOPPING); DBUG_PRINT("info", ("Scheduler thread has cleaned up. Set state to INIT")); sql_print_information("Event Scheduler: Stopped"); @@ -767,16 +771,17 @@ Event_scheduler::unlock_data(const char *func, uint line) */ void -Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const char* msg, - const char *func, uint line) +Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, + const char *src_func, const char *src_file, uint src_line) { DBUG_ENTER("Event_scheduler::cond_wait"); waiting_on_cond= TRUE; - mutex_last_unlocked_at_line= line; + mutex_last_unlocked_at_line= src_line; mutex_scheduler_data_locked= FALSE; - mutex_last_unlocked_in_func= func; + mutex_last_unlocked_in_func= src_func; if (thd) - thd->enter_cond(&COND_state, &LOCK_scheduler_state, msg); + thd->enter_cond(&COND_state, &LOCK_scheduler_state, stage, + NULL, src_func, src_file, src_line); DBUG_PRINT("info", ("mysql_cond_%swait", abstime? "timed":"")); if (!abstime) @@ -789,11 +794,11 @@ Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const char* msg, This will free the lock so we need to relock. Not the best thing to do but we need to obey cond_wait() */ - thd->exit_cond(""); + thd->exit_cond(NULL, src_func, src_file, src_line); LOCK_DATA(); } - mutex_last_locked_in_func= func; - mutex_last_locked_at_line= line; + mutex_last_locked_in_func= src_func; + mutex_last_locked_at_line= src_line; mutex_scheduler_data_locked= TRUE; waiting_on_cond= FALSE; DBUG_VOID_RETURN; diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h index aca4b74dd95..0b160ff49d5 100644 --- a/sql/event_scheduler.h +++ b/sql/event_scheduler.h @@ -12,8 +12,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /** @addtogroup Event_Scheduler @@ -114,8 +114,8 @@ private: unlock_data(const char *func, uint line); void - cond_wait(THD *thd, struct timespec *abstime, const char* msg, - const char *func, uint line); + cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, + const char *src_func, const char *src_file, uint src_line); mysql_mutex_t LOCK_scheduler_state; diff --git a/sql/events.cc b/sql/events.cc index 46b13056d7d..b9c51b77f05 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -938,23 +938,37 @@ static PSI_thread_info all_events_threads[]= { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL}, { &key_thread_event_worker, "event_worker", 0} }; +#endif /* HAVE_PSI_INTERFACE */ + +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}; + +#ifdef HAVE_PSI_INTERFACE +PSI_stage_info *all_events_stages[]= +{ + & stage_waiting_on_empty_queue, + & stage_waiting_for_next_activation, + & stage_waiting_for_scheduler_to_stop +}; static void init_events_psi_keys(void) { const char* category= "sql"; int count; - if (PSI_server == NULL) - return; - count= array_elements(all_events_mutexes); - PSI_server->register_mutex(category, all_events_mutexes, count); + mysql_mutex_register(category, all_events_mutexes, count); count= array_elements(all_events_conds); - PSI_server->register_cond(category, all_events_conds, count); + mysql_cond_register(category, all_events_conds, count); count= array_elements(all_events_threads); - PSI_server->register_thread(category, all_events_threads, count); + mysql_thread_register(category, all_events_threads, count); + + count= array_elements(all_events_stages); + mysql_stage_register(category, all_events_stages, count); + } #endif /* HAVE_PSI_INTERFACE */ @@ -1054,13 +1068,19 @@ Events::load_events_from_db(THD *thd) NOTE: even if we run in read-only mode, we should be able to lock the mysql.event table for writing. In order to achieve this, we should call mysql_lock_tables() under the super user. + + Same goes for transaction access mode. + Temporarily reset it to read-write. */ saved_master_access= thd->security_ctx->master_access; thd->security_ctx->master_access |= SUPER_ACL; + bool save_tx_read_only= thd->tx_read_only; + thd->tx_read_only= false; ret= db_repository->open_event_table(thd, TL_WRITE, &table); + thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; if (ret) diff --git a/sql/events.h b/sql/events.h index a94fbc17135..4720c301052 100644 --- a/sql/events.h +++ b/sql/events.h @@ -31,6 +31,11 @@ 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 */ +/* Always defined, for SHOW PROCESSLIST. */ +extern PSI_stage_info stage_waiting_on_empty_queue; +extern PSI_stage_info stage_waiting_for_next_activation; +extern PSI_stage_info stage_waiting_for_scheduler_to_stop; + #include "sql_string.h" /* LEX_STRING */ #include "my_time.h" /* interval_type */ diff --git a/sql/field.cc b/sql/field.cc index d4468ba3c5b..1769e4e55cb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4882,8 +4882,7 @@ my_decimal *Field_timestamp_hires::val_decimal(my_decimal *d) { MYSQL_TIME ltime; get_date(<ime, 0); - longlong intg= TIME_to_ulonglong(<ime); - return seconds2my_decimal(ltime.neg, intg, ltime.second_part, d); + return TIME_to_my_decimal(<ime, d); } int Field_timestamp_hires::store_decimal(const my_decimal *d) @@ -5103,8 +5102,7 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d) bzero(<ime, sizeof(ltime)); ltime.time_type= mysql_type_to_time_type(type()); } - longlong intg= TIME_to_ulonglong(<ime); - return seconds2my_decimal(ltime.neg, intg, ltime.second_part, d); + return TIME_to_my_decimal(<ime, d); } /**************************************************************************** @@ -9083,9 +9081,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, A default other than '' is always an error, and any non-NULL specified default is an error in strict mode. */ - if (res->length() || (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))) + if (res->length() || thd->is_strict_mode()) { my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), fld_name); /* purecov: inspected */ diff --git a/sql/filesort.cc b/sql/filesort.cc index f31afc226cc..49aaa0af574 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -205,9 +205,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, goto err; if (select && select->quick) - status_var_increment(thd->status_var.filesort_range_count); + thd->inc_status_sort_range(); else - status_var_increment(thd->status_var.filesort_scan_count); + thd->inc_status_sort_scan(); thd->query_plan_flags|= QPLAN_FILESORT; // If number of rows is not known, use as much of sort buffer as possible. @@ -404,8 +404,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } } else - statistic_add(thd->status_var.filesort_rows, - (ulong) num_rows, &LOCK_status); + thd->inc_status_sort_rows(num_rows); *examined_rows= param.examined_rows; #ifdef SKIP_DBUG_IN_FILESORT DBUG_POP(); /* Ok to DBUG */ @@ -1460,7 +1459,7 @@ int merge_buffers(Sort_param *param, IO_CACHE *from_file, THD* const thd=current_thd; DBUG_ENTER("merge_buffers"); - status_var_increment(thd->status_var.filesort_merge_passes); + thd->inc_status_sort_merge_passes(); thd->query_plan_fsort_passes++; error=0; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ce3f17aeb92..148a2329660 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3011,6 +3011,35 @@ err_alloc: } +void ha_partition::unbind_psi() +{ + uint i; + + DBUG_ENTER("ha_partition::unbind_psi"); + handler::unbind_psi(); + for (i= 0; i < m_tot_parts; i++) + { + DBUG_ASSERT(m_file[i] != NULL); + m_file[i]->unbind_psi(); + } + DBUG_VOID_RETURN; +} + +void ha_partition::rebind_psi() +{ + uint i; + + DBUG_ENTER("ha_partition::rebind_psi"); + handler::rebind_psi(); + for (i= 0; i < m_tot_parts; i++) + { + DBUG_ASSERT(m_file[i] != NULL); + m_file[i]->rebind_psi(); + } + DBUG_VOID_RETURN; +} + + /** Clone the open and locked partitioning handler. diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 53f0c4f2484..96e47d3d676 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -309,6 +309,8 @@ public: If the object was opened it will also be closed before being deleted. */ virtual int open(const char *name, int mode, uint test_if_locked); + virtual void unbind_psi(); + virtual void rebind_psi(); virtual int close(void); /* diff --git a/sql/handler.cc b/sql/handler.cc index 150bbee39a9..5297a8e8cfc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009-2011 Monty Program Ab + Copyright (c) 2009, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,8 +11,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @file handler.cc @@ -20,10 +20,6 @@ Handler-calling-functions */ -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - #include "sql_priv.h" #include "unireg.h" #include "rpl_handler.h" @@ -42,6 +38,7 @@ #include "transaction.h" #include "myisam.h" #include "probes_mysql.h" +#include <mysql/psi/mysql_table.h> #include "debug_sync.h" // DEBUG_SYNC #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -230,7 +227,7 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, return NULL; } - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); switch (database_type) { case DB_TYPE_MRG_ISAM: @@ -363,6 +360,7 @@ int ha_init_errors(void) SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS)); SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG)); SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT)); + SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID"); SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK)); SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL)); @@ -771,7 +769,7 @@ void ha_kill_query(THD* thd, enum thd_kill_levels level) end. Such nested transaction was internally referred to as a "statement transaction" and gave birth to the term. - <Historical note ends> + (Historical note ends) Since then a statement transaction is started for each statement that accesses transactional tables or uses the binary log. If @@ -1045,11 +1043,14 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) { trans= &thd->transaction.all; thd->server_status|= SERVER_STATUS_IN_TRANS; + if (thd->tx_read_only) + thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY; + DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS")); } else trans= &thd->transaction.stmt; - ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all); + ha_info= thd->ha_data[ht_arg->slot].ha_info + (all ? 1 : 0); if (ha_info->is_started()) DBUG_VOID_RETURN; /* already registered, return */ @@ -1206,6 +1207,9 @@ int ha_commit_trans(THD *thd, bool all) ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));); + DBUG_PRINT("info", + ("all: %d thd->in_sub_stmt: %d ha_info: %p is_real_trans: %d", + all, thd->in_sub_stmt, ha_info, is_real_trans)); /* We must not commit the normal transaction if a statement transaction is pending. Otherwise statement transaction @@ -1242,7 +1246,9 @@ int ha_commit_trans(THD *thd, bool all) if (!ha_info) { - /* Free resources and perform other cleanup even for 'empty' transactions. */ + /* + Free resources and perform other cleanup even for 'empty' transactions. + */ if (is_real_trans) thd->transaction.cleanup(); DBUG_RETURN(0); @@ -1543,7 +1549,7 @@ int ha_rollback_trans(THD *thd, bool all) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); DBUG_RETURN(error); } @@ -2211,6 +2217,16 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, ha_delete_table_error_handler.buff); } delete file; + +#ifdef HAVE_PSI_TABLE_INTERFACE + if (likely(error == 0)) + { + my_bool temp_table= (my_bool)is_prefix(alias, tmp_file_prefix); + PSI_CALL(drop_table_share)(temp_table, db, strlen(db), + alias, strlen(alias)); + } +#endif + DBUG_RETURN(error); } @@ -2278,6 +2294,30 @@ THD *handler::ha_thd(void) const return (table && table->in_use) ? table->in_use : current_thd; } +void handler::unbind_psi() +{ +#ifdef HAVE_PSI_TABLE_INTERFACE + /* + Notify the instrumentation that this table is not owned + by this thread any more. + */ + PSI_CALL(unbind_table)(m_psi); +#endif +} + +void handler::rebind_psi() +{ +#ifdef HAVE_PSI_TABLE_INTERFACE + /* + Notify the instrumentation that this table is now owned + by this thread. + */ + PSI_table_share *share_psi= ha_table_share_psi(table_share); + m_psi= PSI_CALL(rebind_table)(share_psi, this, m_psi); +#endif +} + + PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const { return share->m_psi; @@ -2320,6 +2360,13 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, } else { + DBUG_ASSERT(m_psi == NULL); + DBUG_ASSERT(table_share != NULL); +#ifdef HAVE_PSI_TABLE_INTERFACE + PSI_table_share *share_psi= ha_table_share_psi(table_share); + m_psi= PSI_CALL(open_table)(share_psi, this); +#endif + if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA) table->db_stat|=HA_READ_ONLY; (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL @@ -2328,7 +2375,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, if (!ref && !(ref= (uchar*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2))) { - close(); + ha_close(); error=HA_ERR_OUT_OF_MEM; } else @@ -2340,7 +2387,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, DBUG_RETURN(error); } -int handler::ha_close() +int handler::ha_close(void) { DBUG_ENTER("ha_close"); /* @@ -2349,9 +2396,158 @@ int handler::ha_close() */ if (table->in_use) status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read); +#ifdef HAVE_PSI_TABLE_INTERFACE + PSI_CALL(close_table)(m_psi); + m_psi= NULL; /* instrumentation handle, invalid after close_table() */ +#endif + DBUG_RETURN(close()); } +int handler::ha_rnd_next(uchar *buf) +{ + int result; + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, + { result= rnd_next(buf); }) + if (!result) + { + update_rows_read(); + increment_statistics(&SSV::ha_read_rnd_next_count); + } + else if (result == HA_ERR_RECORD_DELETED) + increment_statistics(&SSV::ha_read_rnd_deleted_count); + else + increment_statistics(&SSV::ha_read_rnd_next_count); + + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_rnd_pos(uchar *buf, uchar *pos) +{ + int result; + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, + { result= rnd_pos(buf, pos); }) + increment_statistics(&SSV::ha_read_rnd_count); + if (!result) + update_rows_read(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_read_map(uchar *buf, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_read_map(buf, key, keypart_map, find_flag); }) + increment_statistics(&SSV::ha_read_key_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +/* + @note: Other index lookup/navigation functions require prior + handler->index_init() call. This function is different, it requires + that the scan is not initialized, and accepts "uint index" as an argument. +*/ + +int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + int result; + DBUG_ASSERT(inited==NONE); + DBUG_ASSERT(end_range == NULL); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, index, 0, + { result= index_read_idx_map(buf, index, key, keypart_map, find_flag); }) + increment_statistics(&SSV::ha_read_key_count); + if (!result) + { + update_rows_read(); + index_rows_read[index]++; + } + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_next(uchar * buf) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_next(buf); }) + increment_statistics(&SSV::ha_read_next_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_prev(uchar * buf) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_prev(buf); }) + increment_statistics(&SSV::ha_read_prev_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_first(uchar * buf) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_first(buf); }) + increment_statistics(&SSV::ha_read_first_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_last(uchar * buf) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_last(buf); }) + increment_statistics(&SSV::ha_read_last_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + +int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) +{ + int result; + DBUG_ASSERT(inited==INDEX); + + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, + { result= index_next_same(buf, key, keylen); }) + increment_statistics(&SSV::ha_read_next_count); + if (!result) + update_index_statistics(); + table->status=result ? STATUS_NOT_FOUND: 0; + return result; +} + /* Initialize handler for random reading, with error handling */ int handler::ha_rnd_init_with_error(bool scan) @@ -2696,7 +2892,8 @@ int handler::update_auto_increment() if (unlikely(nr == ULONGLONG_MAX)) DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); - DBUG_PRINT("info",("auto_increment: %llu",nr)); + DBUG_PRINT("info",("auto_increment: %llu nb_reserved_values: %llu", + nr, append ? nb_reserved_values : 0)); /* Store field without warning (Warning will be printed by insert) */ save_count_cuted_fields= thd->count_cuted_fields; @@ -2714,8 +2911,6 @@ int handler::update_auto_increment() } if (append) { - DBUG_PRINT("info",("nb_reserved_values: %llu",nb_reserved_values)); - auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values, variables->auto_increment_increment); auto_inc_intervals_count++; @@ -2811,7 +3006,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment, if (table->s->next_number_keypart == 0) { // Autoincrement at key-start - error=ha_index_last(table->record[1]); + error= ha_index_last(table->record[1]); /* MySQL implicitely assumes such method does locking (as MySQL decides to use nr+increment without checking again with the handler, in @@ -2981,44 +3176,28 @@ void handler::print_error(int error, myf errflag) } case HA_ERR_FOREIGN_DUPLICATE_KEY: { - uint key_nr= get_dup_key(error); - if ((int) key_nr >= 0) + char rec_buf[MAX_KEY_LENGTH]; + String rec(rec_buf, sizeof(rec_buf), system_charset_info); + /* Table is opened and defined at this point */ + key_unpack(&rec, table, 0 /* just print the subset of fields that are + part of the first index, printing the whole + row from there is not easy */); + + char child_table_name[NAME_LEN + 1]; + char child_key_name[NAME_LEN + 1]; + if (get_foreign_dup_key(child_table_name, sizeof(child_table_name), + child_key_name, sizeof(child_key_name))) { - uint max_length; - /* Write the key in the error message */ - char key[MAX_KEY_LENGTH]; - String str(key,sizeof(key),system_charset_info); - /* Table is opened and defined at this point */ - - /* - Use primary_key instead of key_nr because key_nr is a key - number in the child FK table, not in our 'table'. See - Bug#12661768 UPDATE IGNORE CRASHES SERVER IF TABLE IS INNODB - AND IT IS PARENT FOR OTHER ONE This bug gets a better fix in - MySQL 5.6, but it is too risky to get that in 5.1 and 5.5 - (extending the handler interface and adding new error message - codes) - */ - if (table->s->primary_key < MAX_KEY) - key_unpack(&str,table,table->s->primary_key); - else - { - LEX_CUSTRING tmp= {USTRING_WITH_LEN("Unknown key value")}; - str.set((const char*) tmp.str, tmp.length, system_charset_info); - } - max_length= (MYSQL_ERRMSG_SIZE- - (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY))); - if (str.length() >= max_length) - { - str.length(max_length-4); - str.append(STRING_WITH_LEN("...")); + my_error(ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO, errflag, + table_share->table_name.str, rec.c_ptr_safe(), + child_table_name, child_key_name); } - my_error(ER_FOREIGN_DUPLICATE_KEY, errflag, table_share->table_name.str, - str.c_ptr_safe(), key_nr+1); - DBUG_VOID_RETURN; + else + { + my_error(ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO, errflag, + table_share->table_name.str, rec.c_ptr_safe()); } - textno= ER_DUP_KEY; - break; + DBUG_VOID_RETURN; } case HA_ERR_NULL_IN_SPATIAL: my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag); @@ -4086,10 +4265,19 @@ int ha_create_table(THD *thd, const char *path, const char *name; TABLE_SHARE share; DBUG_ENTER("ha_create_table"); +#ifdef HAVE_PSI_TABLE_INTERFACE + my_bool temp_table= (my_bool)is_prefix(table_name, tmp_file_prefix) || + (create_info->options & HA_LEX_CREATE_TMP_TABLE ? TRUE : FALSE); +#endif init_tmp_table_share(thd, &share, db, 0, table_name, path); - if (open_table_def(thd, &share, 0) || - open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table, + if (open_table_def(thd, &share, 0)) + goto err; + +#ifdef HAVE_PSI_TABLE_INTERFACE + share.m_psi= PSI_CALL(get_table_share)(temp_table, &share); +#endif + if (open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table, TRUE)) goto err; @@ -4104,6 +4292,10 @@ int ha_create_table(THD *thd, const char *path, { strxmov(name_buff, db, ".", table_name, NullS); my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error); +#ifdef HAVE_PSI_TABLE_INTERFACE + PSI_CALL(drop_table_share)(temp_table, db, strlen(db), table_name, + strlen(table_name)); +#endif } err: free_table_share(&share); @@ -4159,6 +4351,15 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) { DBUG_RETURN(3); } + +#ifdef HAVE_PSI_TABLE_INTERFACE + /* + Table discovery is not instrumented. + Once discovered, the table will be opened normally, + and instrumented normally. + */ +#endif + if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, FALSE)) { free_table_share(&share); @@ -5113,6 +5314,7 @@ static int binlog_log_row(TABLE* table, int handler::ha_external_lock(THD *thd, int lock_type) { + int error; DBUG_ENTER("handler::ha_external_lock"); /* Whether this is lock or unlock, this should be true, and is to verify that @@ -5142,11 +5344,14 @@ int handler::ha_external_lock(THD *thd, int lock_type) } } + ha_statistic_increment(&SSV::ha_external_lock_count); + /* We cache the table flags if the locking succeeded. Otherwise, we keep them as they were when they were fetched in ha_open(). */ - int error= external_lock(thd, lock_type); + MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type, + { error= external_lock(thd, lock_type); }) if (error == 0) cached_table_flags= table_flags(); @@ -5209,7 +5414,9 @@ int handler::ha_write_row(uchar *buf) mark_trx_read_write(); increment_statistics(&SSV::ha_write_count); - error= write_row(buf); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, + { error= write_row(buf); }) + MYSQL_INSERT_ROW_DONE(error); if (unlikely(error)) DBUG_RETURN(error); @@ -5237,7 +5444,9 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) mark_trx_read_write(); increment_statistics(&SSV::ha_update_count); - error= update_row(old_data, new_data); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, + { error= update_row(old_data, new_data);}) + MYSQL_UPDATE_ROW_DONE(error); if (unlikely(error)) return error; @@ -5256,7 +5465,8 @@ int handler::ha_delete_row(const uchar *buf) mark_trx_read_write(); increment_statistics(&SSV::ha_delete_count); - error= delete_row(buf); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_DELETE_ROW, active_index, 0, + { error= delete_row(buf);}) MYSQL_DELETE_ROW_DONE(error); if (unlikely(error)) return error; @@ -5276,7 +5486,7 @@ int handler::ha_delete_row(const uchar *buf) void handler::use_hidden_primary_key() { /* fallback to use all columns in the table to identify row */ - table->use_all_columns(); + table->column_bitmaps_set(&table->s->all_set, table->write_set); } diff --git a/sql/handler.h b/sql/handler.h index c38dec198b9..8ee1044f10c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -326,8 +326,24 @@ #define HA_CACHE_TBL_ASKTRANSACT 2 #define HA_CACHE_TBL_TRANSACT 4 -/* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */ -#define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1 +/** + Options for the START TRANSACTION statement. + + Note that READ ONLY and READ WRITE are logically mutually exclusive. + This is enforced by the parser and depended upon by trans_begin(). + + We need two flags instead of one in order to differentiate between + situation when no READ WRITE/ONLY clause were given and thus transaction + is implicitly READ WRITE and the case when READ WRITE clause was used + explicitly. +*/ + +// WITH CONSISTENT SNAPSHOT option +static const uint MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT = 1; +// READ ONLY option +static const uint MYSQL_START_TRANS_OPT_READ_ONLY = 2; +// READ WRITE option +static const uint MYSQL_START_TRANS_OPT_READ_WRITE = 4; /* Flags for method is_fatal_error */ #define HA_CHECK_DUP_KEY 1 @@ -1114,7 +1130,22 @@ inline LEX_STRING *hton_name(const handlerton *hton) #define HTON_NOT_USER_SELECTABLE (1 << 5) #define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported #define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables -#define HTON_NO_PARTITION (1 << 8) //You can not partition these tables +#define HTON_NO_PARTITION (1 << 8) //Not partition of these tables + +/* + This flag should be set when deciding that the engine does not allow + row based binary logging (RBL) optimizations. + + Currently, setting this flag, means that table's read/write_set will + be left untouched when logging changes to tables in this engine. In + practice this means that the server will not mess around with + table->write_set and/or table->read_set when using RBL and deciding + whether to log full or minimal rows. + + It's valuable for instance for virtual tables, eg: Performance + Schema which have no meaning for replication. +*/ +#define HTON_NO_BINLOG_ROW_OPT (1 << 9) class Ha_trx_info; @@ -1491,21 +1522,24 @@ typedef struct st_range_seq_if typedef bool (*SKIP_INDEX_TUPLE_FUNC) (range_seq_t seq, range_id_t range_info); -class COST_VECT +class Cost_estimate { public: double io_count; /* number of I/O */ double avg_io_cost; /* cost of an average I/O oper. */ double cpu_cost; /* cost of operations in CPU */ - double mem_cost; /* cost of used memory */ double import_cost; /* cost of remote operations */ + double mem_cost; /* cost of used memory */ enum { IO_COEFF=1 }; enum { CPU_COEFF=1 }; enum { MEM_COEFF=1 }; enum { IMPORT_COEFF=1 }; - COST_VECT() {} // keep gcc happy + Cost_estimate() + { + reset(); + } double total_cost() { @@ -1513,7 +1547,17 @@ public: MEM_COEFF*mem_cost + IMPORT_COEFF*import_cost; } - void zero() + /** + Whether or not all costs in the object are zero + + @return true if all costs are zero, false otherwise + */ + bool is_zero() const + { + return !(io_count || cpu_cost || import_cost || mem_cost); + } + + void reset() { avg_io_cost= 1.0; io_count= cpu_cost= mem_cost= import_cost= 0.0; @@ -1527,13 +1571,14 @@ public: /* Don't multiply mem_cost */ } - void add(const COST_VECT* cost) + void add(const Cost_estimate* cost) { double io_count_sum= io_count + cost->io_count; add_io(cost->io_count, cost->avg_io_cost); io_count= io_count_sum; cpu_cost += cost->cpu_cost; } + void add_io(double add_io_cnt, double add_avg_cost) { /* In edge cases add_io_cnt may be zero */ @@ -1546,20 +1591,28 @@ public: } } + /// Add to CPU cost + void add_cpu(double add_cpu_cost) { cpu_cost+= add_cpu_cost; } + + /// Add to import cost + void add_import(double add_import_cost) { import_cost+= add_import_cost; } + + /// Add to memory cost + void add_mem(double add_mem_cost) { mem_cost+= add_mem_cost; } + /* To be used when we go from old single value-based cost calculations to - the new COST_VECT-based. + the new Cost_estimate-based. */ void convert_from_cost(double cost) { - zero(); - avg_io_cost= 1.0; + reset(); io_count= cost; } }; void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, - COST_VECT *cost); + Cost_estimate *cost); /* Indicates that all scanned ranges will be singlepoint (aka equality) ranges. @@ -1850,6 +1903,9 @@ public: */ PSI_table *m_psi; + virtual void unbind_psi(); + virtual void rebind_psi(); + handler(handlerton *ht_arg, TABLE_SHARE *share_arg) :table_share(share_arg), table(0), estimation_rows_to_insert(0), ht(ht_arg), @@ -2008,6 +2064,29 @@ public: virtual void print_error(int error, myf errflag); virtual bool get_error_message(int error, String *buf); uint get_dup_key(int error); + /** + Retrieves the names of the table and the key for which there was a + duplicate entry in the case of HA_ERR_FOREIGN_DUPLICATE_KEY. + + If any of the table or key name is not available this method will return + false and will not change any of child_table_name or child_key_name. + + @param child_table_name[out] Table name + @param child_table_name_len[in] Table name buffer size + @param child_key_name[out] Key name + @param child_key_name_len[in] Key name buffer size + + @retval true table and key names were available + and were written into the corresponding + out parameters. + @retval false table and key names were not available, + the out parameters were not touched. + */ + virtual bool get_foreign_dup_key(char *child_table_name, + uint child_table_name_len, + char *child_key_name, + uint child_key_name_len) + { DBUG_ASSERT(false); return(false); } void reset_statistics() { rows_read= rows_changed= rows_tmp_read= 0; @@ -2187,18 +2266,17 @@ protected: } public: - /* Similar functions like the above, but does statistics counting */ - inline int ha_index_read_map(uchar * buf, const uchar * key, - key_part_map keypart_map, - enum ha_rkey_function find_flag); - inline int ha_index_read_idx_map(uchar * buf, uint index, const uchar * key, - key_part_map keypart_map, - enum ha_rkey_function find_flag); - inline int ha_index_next(uchar * buf); - inline int ha_index_prev(uchar * buf); - inline int ha_index_first(uchar * buf); - inline int ha_index_last(uchar * buf); - inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen); + int ha_index_read_map(uchar * buf, const uchar * key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); + int ha_index_read_idx_map(uchar * buf, uint index, const uchar * key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); + int ha_index_next(uchar * buf); + int ha_index_prev(uchar * buf); + int ha_index_first(uchar * buf); + int ha_index_last(uchar * buf); + int ha_index_next_same(uchar *buf, const uchar *key, uint keylen); /* TODO: should we make for those functions non-virtual ha_func_name wrappers, too? @@ -2206,10 +2284,11 @@ public: virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *mrr_mode, COST_VECT *cost); + uint *mrr_mode, + Cost_estimate *cost); virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, - uint *mrr_mode, COST_VECT *cost); + uint *mrr_mode, Cost_estimate *cost); virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint mrr_mode, HANDLER_BUFFER *buf); @@ -2269,8 +2348,8 @@ public: /* Same as above, but with statistics */ inline int ha_ft_read(uchar *buf); - inline int ha_rnd_next(uchar *buf); - inline int ha_rnd_pos(uchar *buf, uchar *pos); + int ha_rnd_next(uchar *buf); + int ha_rnd_pos(uchar *buf, uchar *pos); inline int ha_rnd_pos_by_record(uchar *buf); inline int ha_read_first_row(uchar *buf, uint primary_key); diff --git a/sql/hash_filo.h b/sql/hash_filo.h index dab54928a55..b6068348d1d 100644 --- a/sql/hash_filo.h +++ b/sql/hash_filo.h @@ -32,9 +32,15 @@ class hash_filo_element { +private: hash_filo_element *next_used,*prev_used; public: hash_filo_element() {} + hash_filo_element *next() + { return next_used; } + hash_filo_element *prev() + { return prev_used; } + friend class hash_filo; }; diff --git a/sql/item.cc b/sql/item.cc index 96f61c08982..665521c641e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3475,7 +3475,7 @@ double Item_param::val_real() This works for example when user says SELECT ?+0.0 and supplies time value for the placeholder. */ - return ulonglong2double(TIME_to_ulonglong(&value.time)); + return TIME_to_double(&value.time); case NULL_VALUE: return 0.0; default: @@ -3533,9 +3533,7 @@ my_decimal *Item_param::val_decimal(my_decimal *dec) return dec; case TIME_VALUE: { - longlong i= (longlong) TIME_to_ulonglong(&value.time); - int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec); - return dec; + return TIME_to_my_decimal(&value.time, dec); } case NULL_VALUE: return 0; @@ -5516,8 +5514,7 @@ String *Item::check_well_formed_result(String *str, bool send_error) cs->csname, hexbuf); return 0; } - if ((thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + if (thd->is_strict_mode()) { null_value= 1; str= 0; diff --git a/sql/item.h b/sql/item.h index 9b10cdf601b..8ec701e0255 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2230,7 +2230,6 @@ public: Item_param(uint pos_in_query_arg); enum Item_result result_type () const { return item_result_type; } - enum Item_result cast_to_int_type() const { return item_result_type; } enum Type type() const { return item_type; } enum_field_types field_type() const { return param_type; } diff --git a/sql/item_func.cc b/sql/item_func.cc index aca76eac82a..390ece724cb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4073,7 +4073,7 @@ longlong Item_func_get_lock::val_int() Structure is now initialized. Try to get the lock. Set up control struct to allow others to abort locks. */ - thd_proc_info(thd, "User lock"); + THD_STAGE_INFO(thd, stage_user_lock); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -4119,7 +4119,6 @@ longlong Item_func_get_lock::val_int() mysql_mutex_unlock(&LOCK_user_locks); mysql_mutex_lock(&thd->mysys_var->mutex); - thd_proc_info(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; mysql_mutex_unlock(&thd->mysys_var->mutex); @@ -4306,7 +4305,7 @@ longlong Item_func_sleep::val_int() mysql_cond_init(key_item_func_sleep_cond, &cond, NULL); mysql_mutex_lock(&LOCK_user_locks); - thd_proc_info(thd, "User sleep"); + THD_STAGE_INFO(thd, stage_user_sleep); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &cond; @@ -4320,7 +4319,6 @@ longlong Item_func_sleep::val_int() error= 0; } thd_wait_end(thd); - thd_proc_info(thd, 0); mysql_mutex_unlock(&LOCK_user_locks); mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index bcd3b881934..5071e494f04 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -51,7 +51,7 @@ #include "password.h" // my_make_scrambled_password, // my_make_scrambled_password_323 #include <m_ctype.h> -#include "my_md5.h" +#include <my_md5.h> #include "sha1.h" #include "my_aes.h" #include <zlib.h> @@ -126,9 +126,7 @@ bool Item_str_func::fix_fields(THD *thd, Item **ref) In Item_str_func::check_well_formed_result() we may set null_value flag on the same condition as in test() below. */ - maybe_null= (maybe_null || - test(thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); + maybe_null= maybe_null || thd->is_strict_mode(); return res; } @@ -182,7 +180,8 @@ String *Item_func_md5::val_str_ascii(String *str) uchar digest[16]; null_value=0; - MY_MD5_HASH(digest,(uchar *) sptr->ptr(), sptr->length()); + compute_md5_hash((char *) digest, (const char *) sptr->ptr(), + sptr->length()); if (str->alloc(32)) // Ensure that memory is free { null_value=1; @@ -4602,10 +4601,7 @@ my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value) case DYN_COL_DATETIME: case DYN_COL_DATE: case DYN_COL_TIME: - decimal_value= seconds2my_decimal(val.x.time_value.neg, - TIME_to_ulonglong(&val.x.time_value), - val.x.time_value.second_part, - decimal_value); + decimal_value= TIME_to_my_decimal(&val.x.time_value, decimal_value); break; } return decimal_value; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0bde4a7926f..87e96da8f62 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4567,7 +4567,7 @@ double get_fanout_with_deps(JOIN *join, table_map tset) !tab->emb_sj_nest && tab->records_read != 0) { - fanout *= rows2double(tab->records_read); + fanout *= tab->records_read; } } return fanout; diff --git a/sql/lex.h b/sql/lex.h index e1dc6150cc3..101880597d5 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -340,6 +340,8 @@ static SYMBOL symbols[] = { { "MASTER_SSL_CAPATH",SYM(MASTER_SSL_CAPATH_SYM)}, { "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM)}, { "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM)}, + { "MASTER_SSL_CRL", SYM(MASTER_SSL_CRL_SYM)}, + { "MASTER_SSL_CRLPATH",SYM(MASTER_SSL_CRLPATH_SYM)}, { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM)}, { "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)}, { "MASTER_USER", SYM(MASTER_USER_SYM)}, @@ -398,8 +400,8 @@ static SYMBOL symbols[] = { { "OLD_PASSWORD", SYM(OLD_PASSWORD)}, { "ON", SYM(ON)}, { "ONE", SYM(ONE_SYM)}, - { "ONE_SHOT", SYM(ONE_SHOT_SYM)}, { "ONLINE", SYM(ONLINE_SYM)}, + { "ONLY", SYM(ONLY_SYM)}, { "OPEN", SYM(OPEN_SYM)}, { "OPTIMIZE", SYM(OPTIMIZE)}, { "OPTIONS", SYM(OPTIONS_SYM)}, diff --git a/sql/lock.cc b/sql/lock.cc index 3a1a6d41ce3..bf53a925424 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -11,8 +11,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /** @@ -304,7 +304,7 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) DBUG_ENTER("mysql_lock_tables(sql_lock)"); - thd_proc_info(thd, "System lock"); + THD_STAGE_INFO(thd, stage_system_lock); if (sql_lock->table_count && lock_external(thd, sql_lock->table, sql_lock->table_count)) goto end; @@ -323,8 +323,6 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) (void) unlock_external(thd, sql_lock->table, sql_lock->table_count); end: - thd_proc_info(thd, 0); - if (thd->killed) { thd->send_kill_message(); @@ -759,6 +757,7 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags) for ( ; locks_start != locks ; locks_start++) { (*locks_start)->debug_print_param= (void *) table; + (*locks_start)->m_psi= table->file->m_psi; (*locks_start)->lock->name= table->alias.c_ptr(); (*locks_start)->org_type= (*locks_start)->type; } diff --git a/sql/log.cc b/sql/log.cc index 0444499c72b..254449da05a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -844,10 +844,10 @@ bool Log_to_csv_event_handler:: if (table->field[3]->store_time(&t)) goto err; /* rows_sent */ - if (table->field[4]->store((longlong) thd->sent_row_count, TRUE)) + if (table->field[4]->store((longlong) thd->get_sent_row_count(), TRUE)) goto err; /* rows_examined */ - if (table->field[5]->store((longlong) thd->examined_row_count, TRUE)) + if (table->field[5]->store((longlong) thd->get_examined_row_count(), TRUE)) goto err; /* fill database field */ @@ -1274,8 +1274,8 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, if (!query) { is_command= TRUE; - query= command_name[thd->command].str; - query_length= command_name[thd->command].length; + query= command_name[thd->get_command()].str; + query_length= command_name[thd->get_command()].length; } for (current_handler= slow_log_handler_list; *current_handler ;) @@ -2098,9 +2098,7 @@ bool MYSQL_BIN_LOG::check_write_error(THD *thd) static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) { DBUG_ENTER("binlog_savepoint_set"); - - binlog_trans_log_savepos(thd, (my_off_t*) sv); - /* Write it to the binary log */ + int error= 1; char buf[1024]; String log_query(buf, sizeof(buf), &my_charset_bin); @@ -2109,10 +2107,25 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) thd->lex->ident.str, thd->lex->ident.length)) DBUG_RETURN(1); int errcode= query_error_code(thd, thd->killed == NOT_KILLED); - Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), + Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), TRUE, FALSE, TRUE, errcode); - int ret= mysql_bin_log.write(&qinfo); - DBUG_RETURN(ret); + /* + We cannot record the position before writing the statement + because a rollback to a savepoint (.e.g. consider it "S") would + prevent the savepoint statement (i.e. "SAVEPOINT S") from being + written to the binary log despite the fact that the server could + still issue other rollback statements to the same savepoint (i.e. + "S"). + Given that the savepoint is valid until the server releases it, + ie, until the transaction commits or it is released explicitly, + we need to log it anyway so that we don't have "ROLLBACK TO S" + or "RELEASE S" without the preceding "SAVEPOINT S" in the binary + log. + */ + if (!(error= mysql_bin_log.write(&qinfo))) + binlog_trans_log_savepos(thd, (my_off_t*) sv); + + DBUG_RETURN(error); } static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) @@ -2803,8 +2816,8 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, (ulong) thd->thread_id, (thd->db ? thd->db : ""), ((thd->query_plan_flags & QPLAN_QC) ? "Yes" : "No"), query_time_buff, lock_time_buff, - (ulong) thd->sent_row_count, - (ulong) thd->examined_row_count) == (size_t) -1) + (ulong) thd->get_sent_row_count(), + (ulong) thd->get_examined_row_count()) == (size_t) -1) tmp_errno= errno; if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) && (thd->query_plan_flags & @@ -6690,15 +6703,14 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry) void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd) { - const char *old_msg; + PSI_stage_info old_stage; DBUG_ENTER("wait_for_update_relay_log"); - old_msg= thd->enter_cond(&update_cond, &LOCK_log, - "Slave has read all relay log; " - "waiting for the slave I/O " - "thread to update it" ); + thd->ENTER_COND(&update_cond, &LOCK_log, + &stage_slave_has_read_all_relay_log, + &old_stage); mysql_cond_wait(&update_cond, &LOCK_log); - thd->exit_cond(old_msg); + thd->EXIT_COND(&old_stage); DBUG_VOID_RETURN; } @@ -8210,7 +8222,7 @@ binlog_background_thread(void *arg __attribute__((unused))) Wait until there is something in the queue to process, or we are asked to shut down. */ - thd_proc_info(thd, "Waiting for background binlog tasks"); + THD_STAGE_INFO(thd, stage_binlog_waiting_background_tasks); mysql_mutex_lock(&mysql_bin_log.LOCK_binlog_background_thread); for (;;) { @@ -8228,7 +8240,7 @@ binlog_background_thread(void *arg __attribute__((unused))) /* Process any incoming commit_checkpoint_notify() calls. */ while (queue) { - thd_proc_info(thd, "Processing binlog checkpoint notification"); + THD_STAGE_INFO(thd, stage_binlog_processing_checkpoint_notify); /* Grab next pointer first, as mark_xid_done() may free the element. */ next= queue->next_in_queue; mysql_bin_log.mark_xid_done(queue->binlog_id, true); @@ -8245,7 +8257,7 @@ binlog_background_thread(void *arg __attribute__((unused))) break; } - thd_proc_info(thd, "Stopping binlog background thread"); + THD_STAGE_INFO(thd, stage_binlog_stopping_background_thread); mysql_mutex_lock(&LOCK_thread_count); delete thd; diff --git a/sql/log_event.cc b/sql/log_event.cc index 10f0fe1e931..7de72338d97 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7316,16 +7316,15 @@ void Create_file_log_event::pack_info(THD *thd, Protocol *protocol) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Create_file_log_event::do_apply_event(Relay_log_info const *rli) { - char proc_info[17+FN_REFLEN+10], *fname_buf; + char fname_buf[FN_REFLEN]; char *ext; int fd = -1; IO_CACHE file; int error = 1; + THD_STAGE_INFO(thd, stage_making_temp_file_create_before_load_data); bzero((char*)&file, sizeof(file)); - fname_buf= strmov(proc_info, "Making temp file "); ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info"); - thd_proc_info(thd, proc_info); /* old copy may exist already */ mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0)); if ((fd= mysql_file_create(key_file_log_event_info, @@ -7382,7 +7381,6 @@ err: end_io_cache(&file); if (fd >= 0) mysql_file_close(fd, MYF(0)); - thd_proc_info(thd, 0); return error != 0; } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -7496,14 +7494,13 @@ int Append_block_log_event::get_create_or_append() const int Append_block_log_event::do_apply_event(Relay_log_info const *rli) { - char proc_info[17+FN_REFLEN+10], *fname= proc_info+17; + char fname[FN_REFLEN]; int fd; int error = 1; DBUG_ENTER("Append_block_log_event::do_apply_event"); - fname= strmov(proc_info, "Making temp file "); + THD_STAGE_INFO(thd, stage_making_temp_file_append_before_load_data); slave_load_file_stem(fname, file_id, server_id, ".data"); - thd_proc_info(thd, proc_info); if (get_create_or_append()) { /* @@ -7553,7 +7550,6 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli) err: if (fd >= 0) mysql_file_close(fd, MYF(0)); - thd_proc_info(thd, 0); DBUG_RETURN(error); } #endif @@ -10600,8 +10596,14 @@ int Rows_log_event::find_row(const Relay_log_info *rli) table->s->reclength) == 0); */ + int error; DBUG_PRINT("info",("locating record using primary key (position)")); - int error= table->file->ha_rnd_pos_by_record(table->record[0]); + + if (!table->file->inited && + (error= table->file->ha_rnd_init_with_error(0))) + DBUG_RETURN(error); + + error= table->file->ha_rnd_pos_by_record(table->record[0]); if (error) { DBUG_PRINT("info",("rnd_pos returns error %d",error)); diff --git a/sql/mdl.cc b/sql/mdl.cc index 7fd522d053a..a18df0fede1 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -10,16 +10,18 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ +#include "mdl.h" #include "sql_class.h" #include "debug_sync.h" #include <hash.h> #include <mysqld_error.h> #include <mysql/plugin.h> #include <mysql/service_thd_wait.h> +#include <mysql/psi/mysql_stage.h> #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_map_mutex; @@ -53,20 +55,18 @@ static PSI_cond_info all_mdl_conds[]= */ static void init_mdl_psi_keys(void) { - const char *category= "sql"; int count; - if (PSI_server == NULL) - return; - count= array_elements(all_mdl_mutexes); - PSI_server->register_mutex(category, all_mdl_mutexes, count); + mysql_mutex_register("sql", all_mdl_mutexes, count); count= array_elements(all_mdl_rwlocks); - PSI_server->register_rwlock(category, all_mdl_rwlocks, count); + mysql_rwlock_register("sql", all_mdl_rwlocks, count); count= array_elements(all_mdl_conds); - PSI_server->register_cond(category, all_mdl_conds, count); + mysql_cond_register("sql", all_mdl_conds, count); + + MDL_key::init_psi_keys(); } #endif /* HAVE_PSI_INTERFACE */ @@ -76,18 +76,35 @@ static void init_mdl_psi_keys(void) belonging to certain namespace. */ -const char *MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]= +PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]= { - "Waiting for global read lock", - "Waiting for schema metadata lock", - "Waiting for table metadata lock", - "Waiting for stored function metadata lock", - "Waiting for stored procedure metadata lock", - "Waiting for trigger metadata lock", - "Waiting for event metadata lock", - "Waiting for commit lock" + {0, "Waiting for global read lock", 0}, + {0, "Waiting for schema metadata lock", 0}, + {0, "Waiting for table metadata lock", 0}, + {0, "Waiting for stored function metadata lock", 0}, + {0, "Waiting for stored procedure metadata lock", 0}, + {0, "Waiting for trigger metadata lock", 0}, + {0, "Waiting for event metadata lock", 0}, + {0, "Waiting for commit lock", 0} }; +#ifdef HAVE_PSI_INTERFACE +void MDL_key::init_psi_keys() +{ + int i; + int count; + PSI_stage_info *info __attribute__((unused)); + + count= array_elements(MDL_key::m_namespace_to_wait_state_name); + for (i= 0; i<count; i++) + { + /* mysql_stage_register wants an array of pointers, registering 1 by 1. */ + info= & MDL_key::m_namespace_to_wait_state_name[i]; + mysql_stage_register("sql", &info, 1); + } +} +#endif + static bool mdl_initialized= 0; @@ -1172,18 +1189,18 @@ void MDL_wait::reset_status() MDL_wait::enum_wait_status MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout, - bool set_status_on_timeout, const char *wait_state_name) + bool set_status_on_timeout, + const PSI_stage_info *wait_state_name) { - const char *old_msg; + PSI_stage_info old_stage; enum_wait_status result; int wait_result= 0; DBUG_ENTER("MDL_wait::timed_wait"); mysql_mutex_lock(&m_LOCK_wait_status); - old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status, - wait_state_name); - + THD_ENTER_COND(thd, &m_COND_wait_status, &m_LOCK_wait_status, + wait_state_name, & old_stage); thd_wait_begin(thd, THD_WAIT_META_DATA_LOCK); while (!m_wait_status && !thd->killed && wait_result != ETIMEDOUT && wait_result != ETIME) @@ -1214,7 +1231,7 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout, } result= m_wait_status; - thd_exit_cond(thd, old_msg); + thd->EXIT_COND(& old_stage); DBUG_RETURN(result); } diff --git a/sql/mdl.h b/sql/mdl.h index af7d75c1297..477f4df7807 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -37,6 +37,24 @@ class MDL_lock; class MDL_ticket; /** + @def ENTER_COND(C, M, S, O) + Start a wait on a condition. + @param C the condition to wait on + @param M the associated mutex + @param S the new stage to enter + @param O the previous stage + @sa EXIT_COND(). +*/ +#define ENTER_COND(C, M, S, O) enter_cond(C, M, S, O, __func__, __FILE__, __LINE__) + +/** + @def EXIT_COND(S) + End a wait on a condition + @param S the new stage to enter +*/ +#define EXIT_COND(S) exit_cond(S, __func__, __FILE__, __LINE__) + +/** Type of metadata lock request. @sa Comments for MDL_object_lock::can_grant_lock() and @@ -189,6 +207,10 @@ enum enum_mdl_duration { class MDL_key { public: +#ifdef HAVE_PSI_INTERFACE + static void init_psi_keys(); +#endif + /** Object namespaces. Sic: when adding a new member to this enum make sure to @@ -284,16 +306,16 @@ public: Get thread state name to be used in case when we have to wait on resource identified by key. */ - const char * get_wait_state_name() const + const PSI_stage_info * get_wait_state_name() const { - return m_namespace_to_wait_state_name[(int)mdl_namespace()]; + return & m_namespace_to_wait_state_name[(int)mdl_namespace()]; } private: uint16 m_length; uint16 m_db_name_length; char m_ptr[MAX_MDLKEY_LENGTH]; - static const char * m_namespace_to_wait_state_name[NAMESPACE_END]; + static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END]; private: MDL_key(const MDL_key &); /* not implemented */ MDL_key &operator=(const MDL_key &); /* not implemented */ @@ -592,8 +614,10 @@ public: bool set_status(enum_wait_status result_arg); enum_wait_status get_status(); void reset_status(); - enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout, - bool signal_timeout, const char *wait_state_name); + enum_wait_status timed_wait(THD *thd, + struct timespec *abs_timeout, + bool signal_timeout, + const PSI_stage_info *wait_state_name); private: /** Condvar which is used for waiting until this context's pending @@ -837,16 +861,8 @@ private: void mdl_init(); void mdl_destroy(); - -/* - Functions in the server's kernel used by metadata locking subsystem. -*/ - extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, bool needs_thr_lock_abort); -extern "C" const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, - mysql_mutex_t *mutex, const char *msg); -extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg); #ifndef DBUG_OFF extern mysql_mutex_t LOCK_open; diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index b9f49a83b4b..e6cbed7eb13 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -56,7 +56,7 @@ ha_rows handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges_arg, - uint *bufsz, uint *flags, COST_VECT *cost) + uint *bufsz, uint *flags, Cost_estimate *cost) { KEY_MULTI_RANGE range; range_seq_t seq_it; @@ -106,7 +106,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, { /* The following calculation is the same as in multi_range_read_info(): */ *flags |= HA_MRR_USE_DEFAULT_IMPL; - cost->zero(); + cost->reset(); cost->avg_io_cost= 1; /* assume random seeks */ if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2) cost->io_count= keyread_time(keyno, n_ranges, (uint)total_rows); @@ -154,7 +154,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows, uint key_parts, uint *bufsz, - uint *flags, COST_VECT *cost) + uint *flags, Cost_estimate *cost) { /* Currently we expect this function to be called only in preparation of scan @@ -165,7 +165,7 @@ ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows, *bufsz= 0; /* Default implementation doesn't need a buffer */ *flags |= HA_MRR_USE_DEFAULT_IMPL; - cost->zero(); + cost->reset(); cost->avg_io_cost= 1; /* assume random seeks */ /* Produce the same cost as non-MRR code does */ @@ -1402,7 +1402,7 @@ int DsMrr_impl::dsmrr_next(range_id_t *range_info) */ ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, uint key_parts, - uint *bufsz, uint *flags, COST_VECT *cost) + uint *bufsz, uint *flags, Cost_estimate *cost) { ha_rows res __attribute__((unused)); uint def_flags= *flags; @@ -1437,7 +1437,7 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, - uint *bufsz, uint *flags, COST_VECT *cost) + uint *bufsz, uint *flags, Cost_estimate *cost) { ha_rows rows; uint def_flags= *flags; @@ -1551,9 +1551,9 @@ bool DsMrr_impl::check_cpk_scan(THD *thd, uint keyno, uint mrr_flags) bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, - uint *bufsz, COST_VECT *cost) + uint *bufsz, Cost_estimate *cost) { - COST_VECT dsmrr_cost; + Cost_estimate dsmrr_cost; bool res; THD *thd= current_thd; @@ -1655,7 +1655,7 @@ int DsMrr_impl::dsmrr_explain_info(uint mrr_mode, char *str, size_t size) } -static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost); +static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost); /** @@ -1673,7 +1673,7 @@ static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost */ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, - uint *buffer_size, COST_VECT *cost) + uint *buffer_size, Cost_estimate *cost) { ulong max_buff_entries, elem_size; ha_rows rows_in_full_step; @@ -1707,13 +1707,13 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, } else { - cost->zero(); + cost->reset(); *buffer_size= max(*buffer_size, (size_t)(1.2*rows_in_last_step) * elem_size + primary_file->ref_length + table->key_info[keynr].key_length); } - COST_VECT last_step_cost; + Cost_estimate last_step_cost; get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost); cost->add(&last_step_cost); @@ -1742,7 +1742,7 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, */ static -void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost) +void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost) { if (nrows) { @@ -1754,7 +1754,7 @@ void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost) cost->cpu_cost += cmp_op * log2(cmp_op); } else - cost->zero(); + cost->reset(); } @@ -1802,11 +1802,11 @@ void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost) */ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, - COST_VECT *cost) + Cost_estimate *cost) { DBUG_ENTER("get_sweep_read_cost"); - cost->zero(); + cost->reset(); if (table->file->primary_key_is_clustered()) { cost->io_count= table->file->read_time(table->s->primary_key, diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h index dcba92aab16..387ae9791bc 100644 --- a/sql/multi_range_read.h +++ b/sql/multi_range_read.h @@ -562,11 +562,11 @@ public: int dsmrr_next(range_id_t *range_info); ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint key_parts, - uint *bufsz, uint *flags, COST_VECT *cost); + uint *bufsz, uint *flags, Cost_estimate *cost); ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, COST_VECT *cost); + uint *flags, Cost_estimate *cost); int dsmrr_explain_info(uint mrr_mode, char *str, size_t size); private: @@ -624,9 +624,9 @@ private: Forward_lifo_buffer rowid_buffer; bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz, - COST_VECT *cost); + Cost_estimate *cost); bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, - uint *buffer_size, COST_VECT *cost); + uint *buffer_size, Cost_estimate *cost); bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags); bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map); diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 4d0042510ae..5d1adb6bca7 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -183,9 +183,9 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, set_timespec(abstime, timeout); int wait_res= 0; - const char *old_msg; - old_msg= caller_thd->enter_cond(&apc_request.COND_request, - LOCK_thd_data_ptr, "show_explain"); + PSI_stage_info old_stage; + caller_thd->ENTER_COND(&apc_request.COND_request, LOCK_thd_data_ptr, + &stage_show_explain, &old_stage); /* todo: how about processing other errors here? */ while (!apc_request.processed && (wait_res != ETIMEDOUT)) { @@ -217,7 +217,7 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, /* exit_cond() will call mysql_mutex_unlock(LOCK_thd_data_ptr) for us: */ - caller_thd->exit_cond(old_msg); + caller_thd->EXIT_COND(&old_stage); /* Destroy all APC request data */ mysql_cond_destroy(&apc_request.COND_request); diff --git a/sql/my_decimal.h b/sql/my_decimal.h index bd03782cb18..3b104bbdee6 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -343,6 +343,10 @@ bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec); my_decimal *seconds2my_decimal(bool sign, ulonglong sec, ulong microsec, my_decimal *d); +#define TIME_to_my_decimal(TIME, DECIMAL) \ + seconds2my_decimal((TIME)->neg, TIME_to_ulonglong(TIME), \ + (TIME)->second_part, (DECIMAL)) + int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag, longlong *l); diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index 6e2c6ec07f3..6a1ca2e09d3 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -37,7 +37,7 @@ "Usage: mysql_install_db.exe [OPTIONS]\n" \ "OPTIONS:" -extern "C" const char mysql_bootstrap_sql[]; +extern "C" const char* mysql_bootstrap_sql[]; char default_os_user[]= "NT AUTHORITY\\NetworkService"; static int create_db_instance(); @@ -247,7 +247,7 @@ static char *init_bootstrap_command_line(char *cmdline, size_t size) "\"\"%s\" --no-defaults --bootstrap" " \"--language=%s\\share\\english\"" " --basedir=. --datadir=. --default-storage-engine=myisam" - " --max_allowed_packet=9M --loose-skip-innodb" + " --max_allowed_packet=9M " " --net-buffer-length=16k\"", mysqld_path, basedir); return cmdline; } @@ -565,12 +565,16 @@ static int create_db_instance() goto end; } - /* Write the bootstrap script to stdin. */ - if (fwrite(mysql_bootstrap_sql, strlen(mysql_bootstrap_sql), 1, in) != 1) + int i; + for (i=0; mysql_bootstrap_sql[i]; i++) { - verbose("ERROR: Cannot write to mysqld's stdin"); - ret= 1; - goto end; + /* Write the bootstrap script to stdin. */ + if (fwrite(mysql_bootstrap_sql[i], strlen(mysql_bootstrap_sql[i]), 1, in) != 1) + { + verbose("ERROR: Cannot write to mysqld's stdin"); + ret= 1; + goto end; + } } /* Remove default user, if requested. */ @@ -621,6 +625,14 @@ static int create_db_instance() goto end; } + /* + Remove innodb log files if they exist (this works around "different size logs" + error in MSI installation). TODO : remove this with the next Innodb, where + different size is handled gracefully. + */ + DeleteFile("ib_logfile0"); + DeleteFile("ib_logfile1"); + /* Create my.ini file in data directory.*/ ret= create_myini(); if (ret) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c662b3279ef..2607297f2c9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -79,6 +79,10 @@ #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #include "../storage/perfschema/pfs_server.h" #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +#include <mysql/psi/mysql_idle.h> +#include <mysql/psi/mysql_socket.h> +#include <mysql/psi/mysql_statement.h> +#include "mysql_com_server.h" #include "keycaches.h" #include "../storage/myisam/ha_myisam.h" @@ -734,6 +738,76 @@ static char **remaining_argv; int orig_argc; char **orig_argv; +static struct my_option pfs_early_options[]= +{ + {"performance_schema_instrument", OPT_PFS_INSTRUMENT, + "Default startup value for a performance schema instrument.", + &pfs_param.m_pfs_instrument, &pfs_param.m_pfs_instrument, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_stages_current", 0, + "Default startup value for the events_stages_current consumer.", + &pfs_param.m_consumer_events_stages_current_enabled, + &pfs_param.m_consumer_events_stages_current_enabled, 0, GET_BOOL, + OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_stages_history", 0, + "Default startup value for the events_stages_history consumer.", + &pfs_param.m_consumer_events_stages_history_enabled, + &pfs_param.m_consumer_events_stages_history_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_stages_history_long", 0, + "Default startup value for the events_stages_history_long consumer.", + &pfs_param.m_consumer_events_stages_history_long_enabled, + &pfs_param.m_consumer_events_stages_history_long_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"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}, + {"performance_schema_consumer_events_statements_history", 0, + "Default startup value for the events_statements_history consumer.", + &pfs_param.m_consumer_events_statements_history_enabled, + &pfs_param.m_consumer_events_statements_history_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_statements_history_long", 0, + "Default startup value for the events_statements_history_long consumer.", + &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_waits_current", 0, + "Default startup value for the events_waits_current consumer.", + &pfs_param.m_consumer_events_waits_current_enabled, + &pfs_param.m_consumer_events_waits_current_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_waits_history", 0, + "Default startup value for the events_waits_history consumer.", + &pfs_param.m_consumer_events_waits_history_enabled, + &pfs_param.m_consumer_events_waits_history_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_events_waits_history_long", 0, + "Default startup value for the events_waits_history_long consumer.", + &pfs_param.m_consumer_events_waits_history_long_enabled, + &pfs_param.m_consumer_events_waits_history_long_enabled, 0, + GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_global_instrumentation", 0, + "Default startup value for the global_instrumentation consumer.", + &pfs_param.m_consumer_global_instrumentation_enabled, + &pfs_param.m_consumer_global_instrumentation_enabled, 0, + GET_BOOL, OPT_ARG, TRUE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_thread_instrumentation", 0, + "Default startup value for the thread_instrumentation consumer.", + &pfs_param.m_consumer_thread_instrumentation_enabled, + &pfs_param.m_consumer_thread_instrumentation_enabled, 0, + GET_BOOL, OPT_ARG, TRUE, 0, 0, 0, 0, 0}, + {"performance_schema_consumer_statements_digest", 0, + "Default startup value for the statements_digest consumer.", + &pfs_param.m_consumer_statement_digest_enabled, + &pfs_param.m_consumer_statement_digest_enabled, 0, + GET_BOOL, OPT_ARG, TRUE, 0, 0, 0, 0, 0} +}; + + + #ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, @@ -758,8 +832,8 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_master_info_data_lock, key_master_info_run_lock, key_master_info_sleep_lock, key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock, - key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, key_relay_log_info_sleep_lock, + key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, key_PARTITION_LOCK_auto_inc; @@ -896,7 +970,6 @@ static PSI_cond_info all_server_conds[]= { &key_COND_wakeup_ready, "THD::COND_wakeup_ready", 0}, { &key_COND_cache_status_changed, "Query_cache::COND_cache_status_changed", 0}, { &key_COND_manager, "COND_manager", PSI_FLAG_GLOBAL}, - { &key_COND_rpl_status, "COND_rpl_status", PSI_FLAG_GLOBAL}, { &key_COND_server_started, "COND_server_started", PSI_FLAG_GLOBAL}, { &key_delayed_insert_cond, "Delayed_insert::cond", 0}, { &key_delayed_insert_cond_client, "Delayed_insert::cond_client", 0}, @@ -947,6 +1020,10 @@ static PSI_thread_info all_server_threads[]= { &key_thread_signal_hand, "signal_handler", PSI_FLAG_GLOBAL} }; +#ifdef HAVE_MMAP +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, @@ -957,67 +1034,89 @@ PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, PSI_file_key key_file_query_log, key_file_slow_log; PSI_file_key key_file_relaylog, key_file_relaylog_index; -static PSI_file_info all_server_files[]= -{ - { &key_file_binlog, "binlog", 0}, - { &key_file_binlog_index, "binlog_index", 0}, - { &key_file_relaylog, "relaylog", 0}, - { &key_file_relaylog_index, "relaylog_index", 0}, - { &key_file_casetest, "casetest", 0}, - { &key_file_dbopt, "dbopt", 0}, - { &key_file_des_key_file, "des_key_file", 0}, - { &key_file_ERRMSG, "ERRMSG", 0}, - { &key_select_to_file, "select_to_file", 0}, - { &key_file_fileparser, "file_parser", 0}, - { &key_file_frm, "FRM", 0}, - { &key_file_global_ddl_log, "global_ddl_log", 0}, - { &key_file_load, "load", 0}, - { &key_file_loadfile, "LOAD_FILE", 0}, - { &key_file_log_event_data, "log_event_data", 0}, - { &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_pid, "pid", 0}, - { &key_file_query_log, "query_log", 0}, - { &key_file_relay_log_info, "relay_log_info", 0}, - { &key_file_send_file, "send_file", 0}, - { &key_file_slow_log, "slow_log", 0}, - { &key_file_tclog, "tclog", 0}, - { &key_file_trg, "trigger_name", 0}, - { &key_file_trn, "trigger", 0}, - { &key_file_init, "init", 0} -}; +#endif /* HAVE_PSI_INTERFACE */ -/** - Initialise all the performance schema instrumentation points - used by the server. -*/ -void init_server_psi_keys(void) +#ifdef HAVE_PSI_STATEMENT_INTERFACE +PSI_statement_info stmt_info_new_packet; +#endif + +#ifndef EMBEDDED_LIBRARY +void net_before_header_psi(struct st_net *net, void *user_data, size_t /* unused: count */) { - const char* category= "sql"; - int count; + THD *thd; + thd= static_cast<THD*> (user_data); + DBUG_ASSERT(thd != NULL); - if (PSI_server == NULL) - return; + if (thd->m_server_idle) + { + /* + The server is IDLE, waiting for the next command. + Technically, it is a wait on a socket, which may take a long time, + because the call is blocking. + Disable the socket instrumentation, to avoid recording a SOCKET event. + Instead, start explicitly an IDLE event. + */ + MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_IDLE); + MYSQL_START_IDLE_WAIT(thd->m_idle_psi, &thd->m_idle_state); + } +} - count= array_elements(all_server_mutexes); - PSI_server->register_mutex(category, all_server_mutexes, count); +void net_after_header_psi(struct st_net *net, void *user_data, size_t /* unused: count */, my_bool rc) +{ + THD *thd; + thd= static_cast<THD*> (user_data); + DBUG_ASSERT(thd != NULL); - count= array_elements(all_server_rwlocks); - PSI_server->register_rwlock(category, all_server_rwlocks, count); + if (thd->m_server_idle) + { + /* + The server just got data for a network packet header, + from the network layer. + The IDLE event is now complete, since we now have a message to process. + We need to: + - start a new STATEMENT event + - start a new STAGE event, within this statement, + - start recording SOCKET WAITS events, within this stage. + The proper order is critical to get events numbered correctly, + and nested in the proper parent. + */ + MYSQL_END_IDLE_WAIT(thd->m_idle_psi); - count= array_elements(all_server_conds); - PSI_server->register_cond(category, all_server_conds, count); + if (! rc) + { + thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, + stmt_info_new_packet.m_key, + thd->db, thd->db_length); - count= array_elements(all_server_threads); - PSI_server->register_thread(category, all_server_threads, count); + THD_STAGE_INFO(thd, stage_init); + } - count= array_elements(all_server_files); - PSI_server->register_file(category, all_server_files, count); + /* + TODO: consider recording a SOCKET event for the bytes just read, + by also passing count here. + */ + MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_ACTIVE); + } } -#endif /* HAVE_PSI_INTERFACE */ +void init_net_server_extension(THD *thd) +{ +#ifdef HAVE_PSI_INTERFACE + /* Start with a clean state for connection events. */ + thd->m_idle_psi= NULL; + thd->m_statement_psi= NULL; + thd->m_server_idle= false; + /* Hook up the NET_SERVER callback in the net layer. */ + thd->m_net_server_extension.m_user_data= thd; + thd->m_net_server_extension.m_before_header= net_before_header_psi; + thd->m_net_server_extension.m_after_header= net_after_header_psi; + /* Activate this private extension for the mysqld server. */ + thd->net.extension= & thd->m_net_server_extension; +#else + thd->net.extension= NULL; +#endif +} +#endif /* EMBEDDED_LIBRARY */ /* Since buffered_option_error_reporter is only used currently @@ -1182,7 +1281,7 @@ C_MODE_END #endif /* !EMBEDDED_LIBRARY */ #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ -static my_socket unix_sock, base_ip_sock, extra_ip_sock; +static MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock; struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD() #ifndef EMBEDDED_LIBRARY @@ -1246,7 +1345,9 @@ HANDLE smem_event_connect_request= 0; my_bool opt_use_ssl = 0; char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL, - *opt_ssl_cipher= NULL, *opt_ssl_key= NULL; + *opt_ssl_cipher= NULL, *opt_ssl_key= NULL, *opt_ssl_crl= NULL, + *opt_ssl_crlpath= NULL; + static scheduler_functions thread_scheduler_struct, extra_thread_scheduler_struct; scheduler_functions *thread_scheduler= &thread_scheduler_struct, @@ -1285,6 +1386,7 @@ pthread_handler_t signal_hand(void *arg); static int mysql_init_variables(void); static int get_options(int *argc_ptr, char ***argv_ptr); static bool add_terminator(DYNAMIC_ARRAY *options); +static bool add_many_options(DYNAMIC_ARRAY *, my_option *, size_t); extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *); static int init_thread_environment(); static char *get_relative_path(const char *path); @@ -1373,17 +1475,17 @@ static void close_connections(void) DBUG_PRINT("quit",("Closing sockets")); if (!opt_disable_networking ) { - if (base_ip_sock != INVALID_SOCKET) + if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) { (void) mysql_socket_shutdown(base_ip_sock, SHUT_RDWR); - (void) closesocket(base_ip_sock); - base_ip_sock= INVALID_SOCKET; + (void) mysql_socket_close(base_ip_sock); + base_ip_sock= MYSQL_INVALID_SOCKET; } - if (extra_ip_sock != INVALID_SOCKET) + if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) { (void) mysql_socket_shutdown(extra_ip_sock, SHUT_RDWR); - (void) closesocket(extra_ip_sock); - extra_ip_sock= INVALID_SOCKET; + (void) mysql_socket_close(extra_ip_sock); + extra_ip_sock= MYSQL_INVALID_SOCKET; } } #ifdef _WIN32 @@ -1411,12 +1513,12 @@ static void close_connections(void) } #endif #ifdef HAVE_SYS_UN_H - if (unix_sock != INVALID_SOCKET) + if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) { (void) mysql_socket_shutdown(unix_sock, SHUT_RDWR); - (void) closesocket(unix_sock); + (void) mysql_socket_close(unix_sock); (void) unlink(mysqld_unix_port); - unix_sock= INVALID_SOCKET; + unix_sock= MYSQL_INVALID_SOCKET; } #endif end_thr_alarm(0); // Abort old alarms. @@ -1521,22 +1623,14 @@ static void close_connections(void) #ifdef HAVE_CLOSE_SERVER_SOCK -static void close_socket(my_socket sock, const char *info) +static void close_socket(MYSQL_SOCKET sock, const char *info) { DBUG_ENTER("close_socket"); - if (sock != INVALID_SOCKET) + if (mysql_socket_getfd(sock) != INVALID_SOCKET) { DBUG_PRINT("info", ("calling shutdown on %s socket", info)); (void) mysql_socket_shutdown(sock, SHUT_RDWR); -#if defined(__NETWARE__) - /* - The following code is disabled for normal systems as it causes MySQL - to hang on AIX 4.3 during shutdown - */ - DBUG_PRINT("info", ("calling closesocket on %s socket", info)); - (void) closesocket(tmp_sock); -#endif } DBUG_VOID_RETURN; } @@ -1552,9 +1646,9 @@ static void close_server_sock() close_socket(extra_ip_sock, "TCP/IP"); close_socket(unix_sock, "unix/IP"); - if (unix_sock != INVALID_SOCKET) + if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) (void) unlink(mysqld_unix_port); - base_ip_sock= extra_ip_sock= unix_sock= INVALID_SOCKET; + base_ip_sock= extra_ip_sock= unix_sock= MYSQL_INVALID_SOCKET; DBUG_VOID_RETURN; #endif @@ -1776,7 +1870,9 @@ static void mysqld_exit(int exit_code) clean_up_mutexes(); clean_up_error_log_mutex(); my_end((opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0)); - shutdown_performance_schema(); // we do it as late as possible +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + shutdown_performance_schema(); +#endif DBUG_LEAVE; exit(exit_code); /* purecov: inspected */ } @@ -1894,6 +1990,7 @@ void clean_up(bool print_message) mysql_cond_broadcast(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); + free_list(opt_plugin_load_list_ptr); /* The following lines may never be executed as the main thread may have killed us @@ -1950,7 +2047,6 @@ static void clean_up_mutexes() #endif /* HAVE_OPENSSL */ #ifdef HAVE_REPLICATION mysql_mutex_destroy(&LOCK_rpl_status); - mysql_cond_destroy(&COND_rpl_status); #endif /* HAVE_REPLICATION */ mysql_mutex_destroy(&LOCK_active_mi); mysql_rwlock_destroy(&LOCK_sys_init_connect); @@ -2151,14 +2247,14 @@ static void set_root(const char *path) Activate usage of a tcp port */ -static my_socket activate_tcp_port(uint port) +static MYSQL_SOCKET activate_tcp_port(uint port) { struct addrinfo *ai, *a; struct addrinfo hints; int error; int arg; char port_buf[NI_MAXSERV]; - my_socket ip_sock= INVALID_SOCKET; + MYSQL_SOCKET ip_sock= MYSQL_INVALID_SOCKET; DBUG_ENTER("activate_tcp_port"); DBUG_PRINT("general",("IP Socket is %d",port)); @@ -2178,25 +2274,29 @@ static my_socket activate_tcp_port(uint port) for (a= ai; a != NULL; a= a->ai_next) { - ip_sock= socket(a->ai_family, a->ai_socktype, a->ai_protocol); - if (ip_sock != INVALID_SOCKET) + ip_sock= mysql_socket_socket(key_socket_tcpip, a->ai_family, + a->ai_socktype, a->ai_protocol); + if (mysql_socket_getfd(ip_sock) != INVALID_SOCKET) break; } - if (ip_sock == INVALID_SOCKET) + if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET) { DBUG_PRINT("error",("Got error: %d from socket()",socket_errno)); sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */ unireg_abort(1); /* purecov: tested */ } + mysql_socket_set_thread_owner(ip_sock); + #ifndef __WIN__ /* We should not use SO_REUSEADDR on windows as this would enable a user to open two mysqld servers with the same TCP/IP port. */ arg= 1; - (void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg)); + (void) mysql_socket_setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg, + sizeof(arg)); #endif /* __WIN__ */ #ifdef IPV6_V6ONLY @@ -2212,8 +2312,8 @@ static my_socket activate_tcp_port(uint port) if (a->ai_family == AF_INET6) { arg= 0; - (void) setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, - sizeof(arg)); + (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY, + (char*)&arg, sizeof(arg)); } #endif /* @@ -2228,7 +2328,7 @@ static my_socket activate_tcp_port(uint port) uint waited, retry, this_wait; for (waited= 0, retry= 1; ; retry++, waited+= this_wait) { - if (((ret= bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) || + if (((ret= mysql_socket_bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) || (socket_errno != SOCKET_EADDRINUSE) || (waited >= mysqld_port_timeout)) break; @@ -2247,7 +2347,7 @@ static my_socket activate_tcp_port(uint port) "port: %u ?", port); unireg_abort(1); } - if (listen(ip_sock,(int) back_log) < 0) + if (mysql_socket_listen(ip_sock,(int) back_log) < 0) { sql_perror("Can't start server: listen() on TCP/IP port"); sql_print_error("listen() on TCP/IP failed with error %d", @@ -2348,21 +2448,26 @@ static void network_init(void) (uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port); unireg_abort(1); } - if ((unix_sock= socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + unix_sock= mysql_socket_socket(key_socket_unix, AF_UNIX, SOCK_STREAM, 0); + if (mysql_socket_getfd(unix_sock) < 0) { sql_perror("Can't start server : UNIX Socket "); /* purecov: inspected */ unireg_abort(1); /* purecov: inspected */ } + + mysql_socket_set_thread_owner(unix_sock); + bzero((char*) &UNIXaddr, sizeof(UNIXaddr)); UNIXaddr.sun_family = AF_UNIX; strmov(UNIXaddr.sun_path, mysqld_unix_port); (void) unlink(mysqld_unix_port); arg= 1; - (void) setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg, - sizeof(arg)); + (void) mysql_socket_setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR, + (char*)&arg, sizeof(arg)); umask(0); - if (bind(unix_sock, reinterpret_cast<struct sockaddr *>(&UNIXaddr), - sizeof(UNIXaddr)) < 0) + if (mysql_socket_bind(unix_sock, + reinterpret_cast<struct sockaddr *>(&UNIXaddr), + sizeof(UNIXaddr)) < 0) { sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */ sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysqld_unix_port); @@ -2372,7 +2477,7 @@ static void network_init(void) #if defined(S_IFSOCK) && defined(SECURE_SOCKETS) (void) chmod(mysqld_unix_port,S_IFSOCK); /* Fix solaris 2.6 bug */ #endif - if (listen(unix_sock,(int) back_log) < 0) + if (mysql_socket_listen(unix_sock,(int) back_log) < 0) sql_print_warning("listen() on Unix socket failed with error %d", socket_errno); } @@ -2524,13 +2629,12 @@ static bool cache_thread() DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; -#ifdef HAVE_PSI_INTERFACE +#ifdef HAVE_PSI_THREAD_INTERFACE /* Delete the instrumentation for the job that just completed, before parking this pthread in the cache (blocked on COND_thread_cache). */ - if (likely(PSI_server != NULL)) - PSI_server->delete_current_thread(); + PSI_CALL(delete_current_thread)(); #endif while (!abort_loop && ! wake_thread && ! kill_cached_threads) @@ -2546,18 +2650,14 @@ static bool cache_thread() thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); -#ifdef HAVE_PSI_INTERFACE +#ifdef HAVE_PSI_THREAD_INTERFACE /* Create new instrumentation for the new THD job, and attach it to this running pthread. */ - if (likely(PSI_server != NULL)) - { - PSI_thread *psi= PSI_server->new_thread(key_thread_one_connection, - thd, thd->thread_id); - if (likely(psi != NULL)) - PSI_server->set_thread(psi); - } + PSI_thread *psi= PSI_CALL(new_thread)(key_thread_one_connection, + thd, thd->thread_id); + PSI_CALL(set_thread)(psi); #endif /* @@ -3074,10 +3174,9 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) if (!abort_loop) { abort_loop=1; // mark abort for threads -#ifdef HAVE_PSI_INTERFACE +#ifdef HAVE_PSI_THREAD_INTERFACE /* Delete the instrumentation for the signal thread */ - if (likely(PSI_server != NULL)) - PSI_server->delete_current_thread(); + PSI_CALL(delete_current_thread)(); #endif #ifdef USE_ONE_SIGNAL_HAND pthread_t tmp; @@ -3437,6 +3536,69 @@ SHOW_VAR com_status_vars[]= { {NullS, NullS, SHOW_LONG} }; + +#ifdef HAVE_PSI_STATEMENT_INTERFACE +PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1]; +PSI_statement_info com_statement_info[(uint) COM_END + 1]; + +/** + Initialize the command names array. + Since we do not want to maintain a separate array, + this is populated from data mined in com_status_vars, + which already has one name for each command. +*/ +void init_sql_statement_info() +{ + char *first_com= (char*) offsetof(STATUS_VAR, com_stat[0]); + char *last_com= (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_END]); + int record_size= (char*) offsetof(STATUS_VAR, com_stat[1]) + - (char*) offsetof(STATUS_VAR, com_stat[0]); + char *ptr; + uint i; + uint com_index; + + static const char* dummy= ""; + for (i= 0; i < ((uint) SQLCOM_END + 1); i++) + { + sql_statement_info[i].m_name= dummy; + sql_statement_info[i].m_flags= 0; + } + + SHOW_VAR *var= &com_status_vars[0]; + while (var->name != NULL) + { + ptr= var->value; + if ((first_com <= ptr) && (ptr <= last_com)) + { + com_index= ((int)(ptr - first_com))/record_size; + DBUG_ASSERT(com_index < (uint) SQLCOM_END); + sql_statement_info[com_index].m_name= var->name; + } + var++; + } + + DBUG_ASSERT(strcmp(sql_statement_info[(uint) SQLCOM_SELECT].m_name, "select") == 0); + DBUG_ASSERT(strcmp(sql_statement_info[(uint) SQLCOM_SIGNAL].m_name, "signal") == 0); + + sql_statement_info[(uint) SQLCOM_END].m_name= "error"; +} + +void init_com_statement_info() +{ + uint index; + + for (index= 0; index < (uint) COM_END + 1; index++) + { + com_statement_info[index].m_name= command_name[index].str; + com_statement_info[index].m_flags= 0; + } + + /* "statement/com/query" can mutate into "statement/sql/..." */ + com_statement_info[(uint) COM_QUERY].m_flags= PSI_FLAG_MUTABLE; +} +#endif + + #ifdef SAFEMALLOC /* Return the id for the current THD, to allow safemalloc to associate @@ -3487,10 +3649,6 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) } -/* - Init common variables -*/ - static int init_common_variables() { umask(((~my_umask) & 0666)); @@ -3560,8 +3718,9 @@ static int init_common_variables() #ifdef HAVE_PSI_INTERFACE /* Complete the mysql_bin_log initialization. - Instrumentation keys are known only after the performance schema initialization, - and can not be set in the MYSQL_BIN_LOG constructor (called before main()). + Instrumentation keys are known only after the performance schema + initialization, and can not be set in the MYSQL_BIN_LOG + constructor (called before main()). */ mysql_bin_log.set_psi_keys(key_BINLOG_LOCK_index, key_BINLOG_update_cond, @@ -3846,6 +4005,10 @@ static int init_common_variables() default_collation= get_charset_by_name(default_collation_name, MYF(0)); if (!default_collation) { +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + buffered_logs.print(); + buffered_logs.cleanup(); +#endif sql_print_error(ER_DEFAULT(ER_UNKNOWN_COLLATION), default_collation_name); return 1; } @@ -4030,7 +4193,6 @@ static int init_thread_environment() mysql_cond_init(key_COND_flush_thread_cache, &COND_flush_thread_cache, NULL); #ifdef HAVE_REPLICATION mysql_mutex_init(key_LOCK_rpl_status, &LOCK_rpl_status, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_rpl_status, &COND_rpl_status, NULL); #endif mysql_mutex_init(key_LOCK_server_started, &LOCK_server_started, MY_MUTEX_INIT_FAST); @@ -4129,7 +4291,8 @@ static void init_ssl() /* having ssl_acceptor_fd != 0 signals the use of SSL */ ssl_acceptor_fd= new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, - opt_ssl_cipher, &error); + opt_ssl_cipher, &error, + opt_ssl_crl, opt_ssl_crlpath); DBUG_PRINT("info",("ssl_acceptor_fd: 0x%lx", (long) ssl_acceptor_fd)); if (!ssl_acceptor_fd) { @@ -4255,7 +4418,7 @@ static int init_server_components() /* set up the hook before initializing plugins which may use it */ error_handler_hook= my_message_sql; - proc_info_hook= set_thd_proc_info; + proc_info_hook= set_thd_stage_info; #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE /* @@ -4506,7 +4669,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); global_system_variables.table_plugin= plugin; mysql_mutex_unlock(&LOCK_global_system_variables); } -#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_ARIA_FOR_TMP_TABLES) +#ifdef USE_ARIA_FOR_TMP_TABLES if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap) { sql_print_error("Aria engine is not enabled or did not start. The Aria engine must be enabled to continue as mysqld was configured with --with-aria-tmp-tables"); @@ -4767,6 +4930,8 @@ int mysqld_main(int argc, char **argv) /* prepare all_early_options array */ my_init_dynamic_array(&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); add_terminator(&all_early_options); @@ -4776,9 +4941,17 @@ int mysqld_main(int argc, char **argv) */ buffered_logs.init(); my_getopt_error_reporter= buffered_option_error_reporter; + my_charset_error_reporter= buffered_option_error_reporter; + pfs_param.m_pfs_instrument= const_cast<char*>(""); + + /* + Initialize the array of performance schema instrument configurations. + */ + init_pfs_instrument_array(); ho_error= handle_options(&remaining_argc, &remaining_argv, - (my_option*)(all_early_options.buffer), NULL); + (my_option*)(all_early_options.buffer), + mysqld_get_one_option); delete_dynamic(&all_early_options); if (ho_error == 0) { @@ -4814,27 +4987,29 @@ int mysqld_main(int argc, char **argv) if available. */ if (PSI_hook) - PSI_server= (PSI*) PSI_hook->get_interface(PSI_CURRENT_VERSION); - - if (PSI_server) { - /* - Now that we have parsed the command line arguments, and have initialized - the performance schema itself, the next step is to register all the - server instruments. - */ - init_server_psi_keys(); - /* Instrument the main thread */ - PSI_thread *psi= PSI_server->new_thread(key_thread_main, NULL, 0); - if (psi) - PSI_server->set_thread(psi); + PSI *psi_server= (PSI*) PSI_hook->get_interface(PSI_CURRENT_VERSION); + if (likely(psi_server != NULL)) + { + set_psi_server(psi_server); - /* - Now that some instrumentation is in place, - recreate objects which were initialised early, - so that they are instrumented as well. - */ - my_thread_global_reinit(); + /* + Now that we have parsed the command line arguments, and have + initialized the performance schema itself, the next step is to + register all the server instruments. + */ + init_server_psi_keys(); + /* Instrument the main thread */ + PSI_thread *psi= PSI_CALL(new_thread)(key_thread_main, NULL, 0); + PSI_CALL(set_thread)(psi); + + /* + Now that some instrumentation is in place, + recreate objects which were initialised early, + so that they are instrumented as well. + */ + my_thread_global_reinit(); + } } #endif /* HAVE_PSI_INTERFACE */ @@ -4978,7 +5153,7 @@ int mysqld_main(int argc, char **argv) if (!opt_bootstrap) mysql_file_delete(key_file_pid, pidfile_name, MYF(MY_WME)); // Not needed anymore - if (unix_sock != INVALID_SOCKET) + if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) unlink(mysqld_unix_port); exit(1); } @@ -5064,8 +5239,8 @@ int mysqld_main(int argc, char **argv) } sql_print_information(ER_DEFAULT(ER_STARTUP),my_progname,server_version, - ((unix_sock == INVALID_SOCKET) ? (char*) "" - : mysqld_unix_port), + ((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ? + (char*) "" : mysqld_unix_port), mysqld_port, MYSQL_COMPILATION_COMMENT); #if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) @@ -5102,13 +5277,12 @@ int mysqld_main(int argc, char **argv) #endif #endif /* __WIN__ */ -#ifdef HAVE_PSI_INTERFACE +#ifdef HAVE_PSI_THREAD_INTERFACE /* Disable the main thread instrumentation, to avoid recording events during the shutdown. */ - if (PSI_server) - PSI_server->delete_current_thread(); + PSI_CALL(delete_current_thread)(); #endif /* Wait until cleanup is done */ @@ -5562,8 +5736,9 @@ static void create_new_thread(THD *thd) inline void kill_broken_server() { /* hack to get around signals ignored in syscalls for problem OS's */ - if (unix_sock == INVALID_SOCKET || - (!opt_disable_networking && base_ip_sock == INVALID_SOCKET)) + if (mysql_socket_getfd(unix_sock) == INVALID_SOCKET || + (!opt_disable_networking && + mysql_socket_getfd(base_ip_sock) == INVALID_SOCKET)) { select_thread_in_use = 0; /* The following call will never return */ @@ -5582,7 +5757,8 @@ inline void kill_broken_server() void handle_connections_sockets() { - my_socket UNINIT_VAR(sock), UNINIT_VAR(new_sock); + MYSQL_SOCKET sock= mysql_socket_invalid(); + MYSQL_SOCKET new_sock= mysql_socket_invalid(); uint error_count=0; THD *thd; struct sockaddr_storage cAddr; @@ -5591,36 +5767,38 @@ void handle_connections_sockets() int extra_ip_flags __attribute__((unused))=0; int flags=0,retval; st_vio *vio_tmp; + bool is_unix_sock; #ifdef HAVE_POLL int socket_count= 0; struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock + MYSQL_SOCKET pfs_fds[3]; // for performance schema #define setup_fds(X) \ - fds[socket_count].fd= X; \ + mysql_socket_set_thread_owner(X); \ + pfs_fds[socket_count]= (X); \ + fds[socket_count].fd= mysql_socket_getfd(X); \ fds[socket_count].events= POLLIN; \ socket_count++ #else +#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs) fd_set readFDs,clientFDs; - uint max_used_connection= (uint) - max(max(base_ip_sock, unix_sock), extra_ip_sock) + 1; -#define setup_fds(X) FD_SET(X,&clientFDs) FD_ZERO(&clientFDs); #endif DBUG_ENTER("handle_connections_sockets"); - if (base_ip_sock != INVALID_SOCKET) + if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) { setup_fds(base_ip_sock); - ip_flags = fcntl(base_ip_sock, F_GETFL, 0); + ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); } - if (extra_ip_sock != INVALID_SOCKET) + if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) { setup_fds(extra_ip_sock); - extra_ip_flags = fcntl(extra_ip_sock, F_GETFL, 0); + extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); } #ifdef HAVE_SYS_UN_H setup_fds(unix_sock); - socket_flags=fcntl(unix_sock, F_GETFL, 0); + socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); #endif DBUG_PRINT("general",("Waiting for connections.")); @@ -5631,8 +5809,7 @@ void handle_connections_sockets() retval= poll(fds, socket_count, -1); #else readFDs=clientFDs; - - retval= select((int) max_used_connection,&readFDs,0,0,0); + retval= select((int) 0,&readFDs,0,0,0); #endif if (retval < 0) @@ -5658,19 +5835,19 @@ void handle_connections_sockets() { if (fds[i].revents & POLLIN) { - sock= fds[i].fd; - flags= fcntl(sock, F_GETFL, 0); + sock= pfs_fds[i]; + flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); break; } } #else // HAVE_POLL - if (FD_ISSET(base_ip_sock,&readFDs)) + if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs)) { sock= base_ip_sock; flags= ip_flags; } else - if (FD_ISSET(extra_ip_sock,&readFDs)) + if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) { sock= extra_ip_sock; flags= extra_ip_flags; @@ -5686,18 +5863,19 @@ void handle_connections_sockets() if (!(test_flags & TEST_BLOCKING)) { #if defined(O_NONBLOCK) - fcntl(sock, F_SETFL, flags | O_NONBLOCK); + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK); #elif defined(O_NDELAY) - fcntl(sock, F_SETFL, flags | O_NDELAY); + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY); #endif } #endif /* NO_FCNTL_NONBLOCK */ for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) { size_socket length= sizeof(struct sockaddr_storage); - new_sock= accept(sock, (struct sockaddr *)(&cAddr), - &length); - if (new_sock != INVALID_SOCKET || + new_sock= mysql_socket_accept(key_socket_client_connection, sock, + (struct sockaddr *)(&cAddr), + &length); + if (mysql_socket_getfd(new_sock) != INVALID_SOCKET || (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) break; MAYBE_BROKEN_SYSCALL; @@ -5705,15 +5883,18 @@ void handle_connections_sockets() if (!(test_flags & TEST_BLOCKING)) { if (retry == MAX_ACCEPT_RETRY - 1) - fcntl(sock, F_SETFL, flags); // Try without O_NONBLOCK + { + // Try without O_NONBLOCK + fcntl(mysql_socket_getfd(sock), F_SETFL, flags); + } } #endif } #if !defined(NO_FCNTL_NONBLOCK) if (!(test_flags & TEST_BLOCKING)) - fcntl(sock, F_SETFL, flags); + fcntl(mysql_socket_getfd(sock), F_SETFL, flags); #endif - if (new_sock == INVALID_SOCKET) + if (mysql_socket_getfd(new_sock) == INVALID_SOCKET) { if ((error_count++ & 255) == 0) // This can happen often sql_perror("Error in accept"); @@ -5725,11 +5906,13 @@ void handle_connections_sockets() #ifdef HAVE_LIBWRAP { - if (sock == base_ip_sock || sock == extra_ip_sock) + if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) || + mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) { struct request_info req; signal(SIGCHLD, SIG_DFL); - request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL); + request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, + mysql_socket_getfd(new_sock), NULL); my_fromhost(&req); if (!my_hosts_access(&req)) { @@ -5751,7 +5934,7 @@ void handle_connections_sockets() ((void (*)(int))req.sink)(req.fd); (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) closesocket(new_sock); + (void) mysql_socket_close(new_sock); continue; } } @@ -5762,12 +5945,13 @@ void handle_connections_sockets() size_socket dummyLen; struct sockaddr_storage dummy; dummyLen = sizeof(dummy); - if ( getsockname(new_sock,(struct sockaddr *)&dummy, - (SOCKET_SIZE_TYPE *)&dummyLen) < 0 ) + if (getsockname(mysql_socket_getfd(new_sock), + (struct sockaddr *)&dummy, + (SOCKET_SIZE_TYPE *)&dummyLen) < 0 ) { sql_perror("Error on new connection socket"); (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) closesocket(new_sock); + (void) mysql_socket_close(new_sock); continue; } } @@ -5780,15 +5964,19 @@ void handle_connections_sockets() if (!(thd= new THD)) { (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) closesocket(new_sock); + (void) mysql_socket_close(new_sock); continue; } /* Set to get io buffers to be part of THD */ set_current_thd(thd); - if (!(vio_tmp=vio_new(new_sock, - sock == unix_sock ? VIO_TYPE_SOCKET : - VIO_TYPE_TCPIP, - sock == unix_sock ? VIO_LOCALHOST: 0)) || + + is_unix_sock= (mysql_socket_getfd(sock) == + mysql_socket_getfd(unix_sock)); + + if (!(vio_tmp= + mysql_socket_vio_new(new_sock, + is_unix_sock ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, + is_unix_sock ? VIO_LOCALHOST: 0)) || my_net_init(&thd->net, vio_tmp, MYF(MY_THREAD_SPECIFIC))) { /* @@ -5801,16 +5989,18 @@ void handle_connections_sockets() else { (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) closesocket(new_sock); + (void) mysql_socket_close(new_sock); } delete thd; set_current_thd(0); continue; } - if (sock == unix_sock) + + init_net_server_extension(thd); + if (is_unix_sock) thd->security_ctx->host=(char*) my_localhost; - if (sock == extra_ip_sock) + if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) { thd->extra_port= 1; thd->scheduler= extra_thread_scheduler; @@ -6185,7 +6375,6 @@ error: */ struct my_option my_long_options[]= - { {"help", '?', "Display this help and exit.", &opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, @@ -6367,9 +6556,6 @@ struct my_option my_long_options[]= "Set the language used for the month names and the days of the week.", &lc_time_names_name, &lc_time_names_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"log", 'l', "Log connections and queries to file (deprecated option, use " - "--general-log/--general-log-file instead).", &opt_logname, &opt_logname, - 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-basename", OPT_LOG_BASENAME, "Basename for all log files and the .pid file. This sets all log file " "names at once (in 'datadir') and is normally the only option you need " @@ -6546,7 +6732,7 @@ struct my_option my_long_options[]= #endif #ifdef HAVE_OPENSSL {"ssl", 0, - "Enable SSL for connection (automatically enabled with other flags).", + "Enable SSL for connection (automatically enabled if an ssl option is used).", &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif @@ -6589,25 +6775,35 @@ struct my_option my_long_options[]= &global_system_variables.tx_isolation, &global_system_variables.tx_isolation, &tx_isolation_typelib, GET_ENUM, REQUIRED_ARG, ISO_REPEATABLE_READ, 0, 0, 0, 0, 0}, + {"transaction-read-only", 0, + "Default transaction access mode. " + "True if transactions are read-only.", + &global_system_variables.tx_read_only, + &global_system_variables.tx_read_only, 0, + GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "Used with --help option for detailed help.", &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin-load", 0, + {"plugin-load", OPT_PLUGIN_LOAD, "Semicolon-separated list of plugins to load, where each plugin is " "specified as ether a plugin_name=library_file pair or only a library_file. " "If the latter case, all plugins from a given library_file will be loaded.", - &opt_plugin_load, &opt_plugin_load, 0, + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-load-add", OPT_PLUGIN_LOAD_ADD, + "Optional semicolon-separated list of plugins to load. This option adds " + "to the list speficied by --plugin-load in an incremental way. " + "It can be specified many times, adding more plugins every time.", + 0, 0, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"table_cache", 0, "Deprecated; use --table-open-cache instead.", &table_cache_size, &table_cache_size, 0, GET_ULONG, - REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} + REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0} }; - static int show_queries(THD *thd, SHOW_VAR *var, char *buff) { var->type= SHOW_LONGLONG; @@ -6989,6 +7185,110 @@ static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff) return 0; } + +#ifdef HAVE_YASSL + +static char * +my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) +{ + return yaSSL_ASN1_TIME_to_string(time, buf, len); +} + +#else /* openssl */ + +static char * +my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) +{ + int n_read; + char *res= NULL; + BIO *bio= BIO_new(BIO_s_mem()); + + if (bio == NULL) + return NULL; + + if (!ASN1_TIME_print(bio, time)) + goto end; + + n_read= BIO_read(bio, buf, (int) (len - 1)); + + if (n_read > 0) + { + buf[n_read]= 0; + res= buf; + } + +end: + BIO_free(bio); + return res; +} + +#endif + + +/** + Handler function for the 'ssl_get_server_not_before' variable + + @param thd the mysql thread structure + @param var the data for the variable + @param[out] buf the string to put the value of the variable into + + @return status + @retval 0 success +*/ + +static int +show_ssl_get_server_not_before(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if(thd->vio_ok() && thd->net.vio->ssl_arg) + { + SSL *ssl= (SSL*) thd->net.vio->ssl_arg; + X509 *cert= SSL_get_certificate(ssl); + ASN1_TIME *not_before= X509_get_notBefore(cert); + + var->value= my_asn1_time_to_string(not_before, buff, + SHOW_VAR_FUNC_BUFF_SIZE); + if (!var->value) + return 1; + var->value= buff; + } + else + var->value= empty_c_string; + return 0; +} + + +/** + Handler function for the 'ssl_get_server_not_after' variable + + @param thd the mysql thread structure + @param var the data for the variable + @param[out] buf the string to put the value of the variable into + + @return status + @retval 0 success +*/ + +static int +show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if(thd->vio_ok() && thd->net.vio->ssl_arg) + { + SSL *ssl= (SSL*) thd->net.vio->ssl_arg; + X509 *cert= SSL_get_certificate(ssl); + ASN1_TIME *not_after= X509_get_notAfter(cert); + + var->value= my_asn1_time_to_string(not_after, buff, + SHOW_VAR_FUNC_BUFF_SIZE); + if (!var->value) + return 1; + } + else + var->value= empty_c_string; + return 0; +} + #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff) @@ -7061,9 +7361,9 @@ SHOW_VAR status_vars[]= { {"Compression", (char*) &show_net_compression, SHOW_SIMPLE_FUNC}, {"Connections", (char*) &thread_id, SHOW_LONG_NOFLUSH}, {"Cpu_time", (char*) offsetof(STATUS_VAR, cpu_time), SHOW_DOUBLE_STATUS}, - {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables), SHOW_LONG_STATUS}, + {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables_), SHOW_LONG_STATUS}, {"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG}, - {"Created_tmp_tables", (char*) offsetof(STATUS_VAR, created_tmp_tables), SHOW_LONG_STATUS}, + {"Created_tmp_tables", (char*) offsetof(STATUS_VAR, created_tmp_tables_), SHOW_LONG_STATUS}, {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, @@ -7082,6 +7382,7 @@ SHOW_VAR status_vars[]= { {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, + {"Handler_external_lock", (char*) offsetof(STATUS_VAR, ha_external_lock_count), SHOW_LONGLONG_STATUS}, {"Handler_icp_attempts", (char*) offsetof(STATUS_VAR, ha_icp_attempts), SHOW_LONG_STATUS}, {"Handler_icp_match", (char*) offsetof(STATUS_VAR, ha_icp_match), SHOW_LONG_STATUS}, {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_mrr_init_count), SHOW_LONG_STATUS}, @@ -7135,24 +7436,24 @@ SHOW_VAR status_vars[]= { #ifdef HAVE_REPLICATION {"Rpl_status", (char*) &show_rpl_status, SHOW_SIMPLE_FUNC}, #endif - {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count), SHOW_LONG_STATUS}, - {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count), SHOW_LONG_STATUS}, - {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count), SHOW_LONG_STATUS}, - {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count), SHOW_LONG_STATUS}, - {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count), SHOW_LONG_STATUS}, + {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count_), SHOW_LONG_STATUS}, + {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count_), SHOW_LONG_STATUS}, + {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count_), SHOW_LONG_STATUS}, + {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count_), SHOW_LONG_STATUS}, + {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count_), SHOW_LONG_STATUS}, {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG}, #ifdef HAVE_REPLICATION - {"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG}, {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC}, {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_SIMPLE_FUNC}, + {"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG}, {"Slave_running", (char*) &show_slave_running, SHOW_SIMPLE_FUNC}, #endif {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG}, {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS}, - {"Sort_merge_passes", (char*) offsetof(STATUS_VAR, filesort_merge_passes), SHOW_LONG_STATUS}, - {"Sort_range", (char*) offsetof(STATUS_VAR, filesort_range_count), SHOW_LONG_STATUS}, - {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows), SHOW_LONG_STATUS}, - {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count), SHOW_LONG_STATUS}, + {"Sort_merge_passes", (char*) offsetof(STATUS_VAR, filesort_merge_passes_), SHOW_LONG_STATUS}, + {"Sort_range", (char*) offsetof(STATUS_VAR, filesort_range_count_), SHOW_LONG_STATUS}, + {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows_), SHOW_LONG_STATUS}, + {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count_), SHOW_LONG_STATUS}, #ifdef HAVE_OPENSSL #ifndef EMBEDDED_LIBRARY {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_SIMPLE_FUNC}, @@ -7167,6 +7468,8 @@ SHOW_VAR status_vars[]= { {"Ssl_default_timeout", (char*) &show_ssl_get_default_timeout, SHOW_SIMPLE_FUNC}, {"Ssl_finished_accepts", (char*) &show_ssl_ctx_sess_accept_good, SHOW_SIMPLE_FUNC}, {"Ssl_finished_connects", (char*) &show_ssl_ctx_sess_connect_good, SHOW_SIMPLE_FUNC}, + {"Ssl_server_not_after", (char*) &show_ssl_get_server_not_after, SHOW_SIMPLE_FUNC}, + {"Ssl_server_not_before", (char*) &show_ssl_get_server_not_before, SHOW_SIMPLE_FUNC}, {"Ssl_session_cache_hits", (char*) &show_ssl_ctx_sess_hits, SHOW_SIMPLE_FUNC}, {"Ssl_session_cache_misses", (char*) &show_ssl_ctx_sess_misses, SHOW_SIMPLE_FUNC}, {"Ssl_session_cache_mode", (char*) &show_ssl_ctx_get_session_cache_mode, SHOW_SIMPLE_FUNC}, @@ -7209,12 +7512,21 @@ SHOW_VAR status_vars[]= { {NullS, NullS, SHOW_LONG} }; -bool add_terminator(DYNAMIC_ARRAY *options) +static bool add_terminator(DYNAMIC_ARRAY *options) { my_option empty_element= {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}; return insert_dynamic(options, (uchar *)&empty_element); } +static bool add_many_options(DYNAMIC_ARRAY *options, my_option *list, + size_t elements) +{ + for (my_option *opt= list; opt < list + elements; opt++) + if (insert_dynamic(options, opt)) + return 1; + return 0; +} + #ifndef EMBEDDED_LIBRARY static void print_version(void) { @@ -7256,6 +7568,8 @@ static void print_help() init_alloc_root(&mem_root, 4096, 4096, MYF(0)); pop_dynamic(&all_options); + add_many_options(&all_options, pfs_early_options, + array_elements(pfs_early_options)); sys_var_add_options(&all_options, sys_var::PARSE_EARLY); add_plugin_options(&all_options, &mem_root); sort_dynamic(&all_options, (qsort_cmp) option_cmp); @@ -7390,7 +7704,7 @@ static int mysql_init_variables(void) character_set_filesystem= &my_charset_bin; opt_specialflag= SPECIAL_ENGLISH; - unix_sock= base_ip_sock= extra_ip_sock= INVALID_SOCKET; + unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET; mysql_home_ptr= mysql_home; pidfile_name_ptr= pidfile_name; log_error_file_ptr= log_error_file; @@ -7844,11 +8158,6 @@ mysqld_get_one_option(int optid, if (argument == NULL) /* no argument */ log_error_file_ptr= const_cast<char*>(""); break; - case OPT_MAX_LONG_DATA_SIZE: - max_long_data_size_used= true; - break; - - case OPT_IGNORE_DB_DIRECTORY: if (*argument == 0) ignore_db_dirs_reset(); @@ -7863,6 +8172,83 @@ mysqld_get_one_option(int optid, } } break; + + case OPT_PLUGIN_LOAD: + free_list(opt_plugin_load_list_ptr); + /* fall through */ + case OPT_PLUGIN_LOAD_ADD: + opt_plugin_load_list_ptr->push_back(new i_string(argument)); + break; + case OPT_MAX_LONG_DATA_SIZE: + max_long_data_size_used= true; + break; + case OPT_PFS_INSTRUMENT: +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + /* Parse instrument name and value from argument string */ + char* name = argument,*p, *val; + + /* Assignment required */ + if (!(p= strchr(argument, '='))) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Missing value for performance_schema_instrument " + "'%s'", argument); + return 0; + } + + /* Option value */ + val= p + 1; + if (!*val) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Missing value for performance_schema_instrument " + "'%s'", argument); + return 0; + } + + /* Trim leading spaces from instrument name */ + while (*name && my_isspace(mysqld_charset, *name)) + name++; + + /* Trim trailing spaces and slashes from instrument name */ + while (p > argument && (my_isspace(mysqld_charset, p[-1]) || p[-1] == '/')) + p--; + *p= 0; + + if (!*name) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid instrument name for " + "performance_schema_instrument '%s'", argument); + return 0; + } + + /* Trim leading spaces from option value */ + while (*val && my_isspace(mysqld_charset, *val)) + val++; + + /* Trim trailing spaces from option value */ + if ((p= my_strchr(mysqld_charset, val, val+strlen(val), ' ')) != NULL) + *p= 0; + + if (!*val) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid value for performance_schema_instrument " + "'%s'", argument); + return 0; + } + + /* Add instrument name and value to array of configuration options */ + if (add_pfs_instr_to_array(name, val)) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid value for performance_schema_instrument " + "'%s'", argument); + return 0; + } +#endif + break; } return 0; } @@ -7946,10 +8332,7 @@ static int get_options(int *argc_ptr, char ***argv_ptr) my_init_dynamic_array(&all_options, sizeof(my_option), array_elements(my_long_options), array_elements(my_long_options)/4, MYF(0)); - for (my_option *opt= my_long_options; - opt < my_long_options + array_elements(my_long_options) - 1; - opt++) - insert_dynamic(&all_options, (uchar*) opt); + add_many_options(&all_options, my_long_options, array_elements(my_long_options)); sys_var_add_options(&all_options, 0); add_terminator(&all_options); @@ -8470,3 +8853,316 @@ void refresh_status(THD *thd) mysql_mutex_unlock(&LOCK_thread_count); } +#ifdef HAVE_PSI_INTERFACE +static PSI_file_info all_server_files[]= +{ +#ifdef HAVE_MMAP + { &key_file_map, "map", 0}, +#endif /* HAVE_MMAP */ + { &key_file_binlog, "binlog", 0}, + { &key_file_binlog_index, "binlog_index", 0}, + { &key_file_relaylog, "relaylog", 0}, + { &key_file_relaylog_index, "relaylog_index", 0}, + { &key_file_casetest, "casetest", 0}, + { &key_file_dbopt, "dbopt", 0}, + { &key_file_des_key_file, "des_key_file", 0}, + { &key_file_ERRMSG, "ERRMSG", 0}, + { &key_select_to_file, "select_to_file", 0}, + { &key_file_fileparser, "file_parser", 0}, + { &key_file_frm, "FRM", 0}, + { &key_file_global_ddl_log, "global_ddl_log", 0}, + { &key_file_load, "load", 0}, + { &key_file_loadfile, "LOAD_FILE", 0}, + { &key_file_log_event_data, "log_event_data", 0}, + { &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_pid, "pid", 0}, + { &key_file_query_log, "query_log", 0}, + { &key_file_relay_log_info, "relay_log_info", 0}, + { &key_file_send_file, "send_file", 0}, + { &key_file_slow_log, "slow_log", 0}, + { &key_file_tclog, "tclog", 0}, + { &key_file_trg, "trigger_name", 0}, + { &key_file_trn, "trigger", 0}, + { &key_file_init, "init", 0} +}; +#endif /* HAVE_PSI_INTERFACE */ + +PSI_stage_info stage_after_create= { 0, "After create", 0}; +PSI_stage_info stage_allocating_local_table= { 0, "allocating local table", 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_query_cache_for_query= { 0, "checking query cache for query", 0}; +PSI_stage_info stage_cleaning_up= { 0, "cleaning up", 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_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_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}; +PSI_stage_info stage_discard_or_import_tablespace= { 0, "discard_or_import_tablespace", 0}; +PSI_stage_info stage_enabling_keys= { 0, "enabling keys", 0}; +PSI_stage_info stage_end= { 0, "end", 0}; +PSI_stage_info stage_executing= { 0, "executing", 0}; +PSI_stage_info stage_execution_of_init_command= { 0, "Execution of init_command", 0}; +PSI_stage_info stage_explaining= { 0, "explaining", 0}; +PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog= { 0, "Finished reading one binlog; switching to next binlog", 0}; +PSI_stage_info stage_flushing_relay_log_and_master_info_repository= { 0, "Flushing relay log and master info repository.", 0}; +PSI_stage_info stage_flushing_relay_log_info_file= { 0, "Flushing relay-log info file.", 0}; +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_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_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_opening_tables= { 0, "Opening tables", 0}; +PSI_stage_info stage_optimizing= { 0, "optimizing", 0}; +PSI_stage_info stage_preparing= { 0, "preparing", 0}; +PSI_stage_info stage_purging_old_relay_logs= { 0, "Purging old relay logs", 0}; +PSI_stage_info stage_query_end= { 0, "query end", 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_registering_slave_on_master= { 0, "Registering slave on master", 0}; +PSI_stage_info stage_removing_duplicates= { 0, "Removing duplicates", 0}; +PSI_stage_info stage_removing_tmp_table= { 0, "removing tmp table", 0}; +PSI_stage_info stage_rename= { 0, "rename", 0}; +PSI_stage_info stage_rename_result_table= { 0, "rename result table", 0}; +PSI_stage_info stage_requesting_binlog_dump= { 0, "Requesting binlog dump", 0}; +PSI_stage_info stage_reschedule= { 0, "reschedule", 0}; +PSI_stage_info stage_searching_rows_for_update= { 0, "Searching rows for update", 0}; +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_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_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}; +PSI_stage_info stage_sorting_result= { 0, "Sorting result", 0}; +PSI_stage_info stage_statistics= { 0, "statistics", 0}; +PSI_stage_info stage_sql_thd_waiting_until_delay= { 0, "Waiting until MASTER_DELAY seconds after master executed event", 0 }; +PSI_stage_info stage_storing_result_in_query_cache= { 0, "storing result in query cache", 0}; +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_update= { 0, "update", 0}; +PSI_stage_info stage_updating= { 0, "updating", 0}; +PSI_stage_info stage_updating_main_table= { 0, "updating main table", 0}; +PSI_stage_info stage_updating_reference_tables= { 0, "updating reference tables", 0}; +PSI_stage_info stage_upgrading_lock= { 0, "upgrading lock", 0}; +PSI_stage_info stage_user_lock= { 0, "User lock", 0}; +PSI_stage_info stage_user_sleep= { 0, "User sleep", 0}; +PSI_stage_info stage_verifying_table= { 0, "verifying table", 0}; +PSI_stage_info stage_waiting_for_delay_list= { 0, "waiting for delay_list", 0}; +PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log= { 0, "waiting for GTID to be written to binary log", 0}; +PSI_stage_info stage_waiting_for_handler_insert= { 0, "waiting for handler insert", 0}; +PSI_stage_info stage_waiting_for_handler_lock= { 0, "waiting for handler lock", 0}; +PSI_stage_info stage_waiting_for_handler_open= { 0, "waiting for handler open", 0}; +PSI_stage_info stage_waiting_for_insert= { 0, "Waiting for INSERT", 0}; +PSI_stage_info stage_waiting_for_master_to_send_event= { 0, "Waiting for master to send event", 0}; +PSI_stage_info stage_waiting_for_master_update= { 0, "Waiting for master update", 0}; +PSI_stage_info stage_waiting_for_relay_log_space= { 0, "Waiting for the slave SQL thread to free enough relay log space", 0}; +PSI_stage_info stage_waiting_for_slave_mutex_on_exit= { 0, "Waiting for slave mutex on exit", 0}; +PSI_stage_info stage_waiting_for_slave_thread_to_start= { 0, "Waiting for slave thread to start", 0}; +PSI_stage_info stage_waiting_for_table_flush= { 0, "Waiting for table flush", 0}; +PSI_stage_info stage_waiting_for_query_cache_lock= { 0, "Waiting for query cache lock", 0}; +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_slave_waiting_workers_to_exit= { 0, "Waiting for workers to exit", 0}; +PSI_stage_info stage_slave_waiting_worker_to_release_partition= { 0, "Waiting for Slave Worker to release partition", 0}; +PSI_stage_info stage_slave_waiting_worker_to_free_events= { 0, "Waiting for Slave Workers to free pending events", 0}; +PSI_stage_info stage_slave_waiting_worker_queue= { 0, "Waiting for Slave Worker queue", 0}; +PSI_stage_info stage_slave_waiting_event_from_coordinator= { 0, "Waiting for an event from Coordinator", 0}; +PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for background binlog tasks", 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}; + +#ifdef HAVE_PSI_INTERFACE + +PSI_stage_info *all_server_stages[]= +{ + & stage_after_create, + & stage_allocating_local_table, + & stage_changing_master, + & stage_checking_master_version, + & stage_checking_permissions, + & stage_checking_privileges_on_cached_query, + & stage_checking_query_cache_for_query, + & stage_cleaning_up, + & stage_closing_tables, + & stage_connecting_to_master, + & stage_converting_heap_to_myisam, + & stage_copying_to_group_table, + & stage_copying_to_tmp_table, + & stage_copy_to_tmp_table, + & stage_creating_delayed_handler, + & stage_creating_sort_index, + & stage_creating_table, + & stage_creating_tmp_table, + & stage_deleting_from_main_table, + & stage_deleting_from_reference_tables, + & stage_discard_or_import_tablespace, + & stage_enabling_keys, + & stage_end, + & stage_executing, + & stage_execution_of_init_command, + & stage_explaining, + & stage_finished_reading_one_binlog_switching_to_next_binlog, + & stage_flushing_relay_log_and_master_info_repository, + & stage_flushing_relay_log_info_file, + & stage_freeing_items, + & stage_fulltext_initialization, + & stage_got_handler_lock, + & stage_got_old_table, + & stage_init, + & stage_insert, + & stage_invalidating_query_cache_entries_table, + & stage_invalidating_query_cache_entries_table_list, + & stage_killing_slave, + & stage_logging_slow_query, + & stage_making_temp_file_append_before_load_data, + & stage_making_temp_file_create_before_load_data, + & stage_manage_keys, + & stage_master_has_sent_all_binlog_to_slave, + & stage_opening_tables, + & stage_optimizing, + & stage_preparing, + & stage_purging_old_relay_logs, + & stage_query_end, + & stage_queueing_master_event_to_the_relay_log, + & stage_reading_event_from_the_relay_log, + & stage_registering_slave_on_master, + & stage_removing_duplicates, + & stage_removing_tmp_table, + & stage_rename, + & stage_rename_result_table, + & stage_requesting_binlog_dump, + & stage_reschedule, + & stage_searching_rows_for_update, + & stage_sending_binlog_event_to_slave, + & stage_sending_cached_result_to_client, + & stage_sending_data, + & stage_setup, + & stage_slave_has_read_all_relay_log, + & stage_show_explain, + & stage_sorting, + & stage_sorting_for_group, + & stage_sorting_for_order, + & stage_sorting_result, + & stage_sql_thd_waiting_until_delay, + & stage_statistics, + & stage_storing_result_in_query_cache, + & stage_storing_row_into_queue, + & stage_system_lock, + & stage_update, + & stage_updating, + & stage_updating_main_table, + & stage_updating_reference_tables, + & stage_upgrading_lock, + & stage_user_lock, + & stage_user_sleep, + & stage_verifying_table, + & stage_waiting_for_delay_list, + & stage_waiting_for_handler_insert, + & stage_waiting_for_handler_lock, + & stage_waiting_for_handler_open, + & stage_waiting_for_insert, + & stage_waiting_for_master_to_send_event, + & stage_waiting_for_master_update, + & stage_waiting_for_slave_mutex_on_exit, + & stage_waiting_for_slave_thread_to_start, + & stage_waiting_for_table_flush, + & stage_waiting_for_query_cache_lock, + & stage_waiting_for_the_next_event_in_relay_log, + & stage_waiting_for_the_slave_thread_to_advance_position, + & stage_waiting_to_finalize_termination, + & stage_waiting_to_get_readlock +}; + +PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; + +static PSI_socket_info all_server_sockets[]= +{ + { &key_socket_tcpip, "server_tcpip_socket", PSI_FLAG_GLOBAL}, + { &key_socket_unix, "server_unix_socket", PSI_FLAG_GLOBAL}, + { &key_socket_client_connection, "client_connection", 0} +}; + +/** + Initialise all the performance schema instrumentation points + used by the server. +*/ +void init_server_psi_keys(void) +{ + const char* category= "sql"; + int count; + + count= array_elements(all_server_mutexes); + mysql_mutex_register(category, all_server_mutexes, count); + + count= array_elements(all_server_rwlocks); + mysql_rwlock_register(category, all_server_rwlocks, count); + + count= array_elements(all_server_conds); + mysql_cond_register(category, all_server_conds, count); + + count= array_elements(all_server_threads); + mysql_thread_register(category, all_server_threads, count); + + count= array_elements(all_server_files); + mysql_file_register(category, all_server_files, count); + + count= array_elements(all_server_stages); + mysql_stage_register(category, all_server_stages, count); + + count= array_elements(all_server_sockets); + mysql_socket_register(category, all_server_sockets, count); + +#ifdef HAVE_PSI_STATEMENT_INTERFACE + init_sql_statement_info(); + count= array_elements(sql_statement_info); + mysql_statement_register(category, sql_statement_info, count); + + category= "com"; + init_com_statement_info(); + count= array_elements(com_statement_info); + mysql_statement_register(category, com_statement_info, count); + + /* + When a new packet is received, + it is instrumented as "statement/com/". + Based on the packet type found, it later mutates to the + proper narrow type, for example + "statement/com/query" or "statement/com/ping". + In cases of "statement/com/query", SQL queries are given to + the parser, which mutates the statement type to an even more + narrow classification, for example "statement/sql/select". + */ + stmt_info_new_packet.m_key= 0; + stmt_info_new_packet.m_name= ""; + stmt_info_new_packet.m_flags= PSI_FLAG_MUTABLE; + mysql_statement_register(category, & stmt_info_new_packet, 1); +#endif +} + +#endif /* HAVE_PSI_INTERFACE */ diff --git a/sql/mysqld.h b/sql/mysqld.h index 6bde25f08fb..716423f9bd2 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -23,6 +23,7 @@ #include "my_atomic.h" /* my_atomic_rwlock_t */ #include "mysql/psi/mysql_file.h" /* MYSQL_FILE */ #include "sql_list.h" /* I_List */ +#include "sql_cmd.h" class THD; struct handlerton; @@ -211,6 +212,7 @@ extern int bootstrap_error; extern I_List<THD> threads; extern char err_shared_dir[]; extern TYPELIB thread_handling_typelib; +extern ulong log_warnings; /* THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread, @@ -291,10 +293,139 @@ extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest, 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_socket_key key_socket_tcpip, key_socket_unix, + key_socket_client_connection; void init_server_psi_keys(); #endif /* HAVE_PSI_INTERFACE */ +/* + MAINTAINER: Please keep this list in order, to limit merge collisions. + Hint: grep PSI_stage_info | sort -u +*/ +extern PSI_stage_info stage_after_create; +extern PSI_stage_info stage_allocating_local_table; +extern PSI_stage_info stage_changing_master; +extern PSI_stage_info stage_checking_master_version; +extern PSI_stage_info stage_checking_permissions; +extern PSI_stage_info stage_checking_privileges_on_cached_query; +extern PSI_stage_info stage_checking_query_cache_for_query; +extern PSI_stage_info stage_cleaning_up; +extern PSI_stage_info stage_closing_tables; +extern PSI_stage_info stage_connecting_to_master; +extern PSI_stage_info stage_converting_heap_to_myisam; +extern PSI_stage_info stage_copying_to_group_table; +extern PSI_stage_info stage_copying_to_tmp_table; +extern PSI_stage_info stage_copy_to_tmp_table; +extern PSI_stage_info stage_creating_delayed_handler; +extern PSI_stage_info stage_creating_sort_index; +extern PSI_stage_info stage_creating_table; +extern PSI_stage_info stage_creating_tmp_table; +extern PSI_stage_info stage_deleting_from_main_table; +extern PSI_stage_info stage_deleting_from_reference_tables; +extern PSI_stage_info stage_discard_or_import_tablespace; +extern PSI_stage_info stage_end; +extern PSI_stage_info stage_enabling_keys; +extern PSI_stage_info stage_executing; +extern PSI_stage_info stage_execution_of_init_command; +extern PSI_stage_info stage_explaining; +extern PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog; +extern PSI_stage_info stage_flushing_relay_log_and_master_info_repository; +extern PSI_stage_info stage_flushing_relay_log_info_file; +extern PSI_stage_info stage_freeing_items; +extern PSI_stage_info stage_fulltext_initialization; +extern PSI_stage_info stage_got_handler_lock; +extern PSI_stage_info stage_got_old_table; +extern PSI_stage_info stage_init; +extern PSI_stage_info stage_insert; +extern PSI_stage_info stage_invalidating_query_cache_entries_table; +extern PSI_stage_info stage_invalidating_query_cache_entries_table_list; +extern PSI_stage_info stage_killing_slave; +extern PSI_stage_info stage_logging_slow_query; +extern PSI_stage_info stage_making_temp_file_append_before_load_data; +extern PSI_stage_info stage_making_temp_file_create_before_load_data; +extern PSI_stage_info stage_manage_keys; +extern PSI_stage_info stage_master_has_sent_all_binlog_to_slave; +extern PSI_stage_info stage_opening_tables; +extern PSI_stage_info stage_optimizing; +extern PSI_stage_info stage_preparing; +extern PSI_stage_info stage_purging_old_relay_logs; +extern PSI_stage_info stage_query_end; +extern PSI_stage_info stage_queueing_master_event_to_the_relay_log; +extern PSI_stage_info stage_reading_event_from_the_relay_log; +extern PSI_stage_info stage_registering_slave_on_master; +extern PSI_stage_info stage_removing_duplicates; +extern PSI_stage_info stage_removing_tmp_table; +extern PSI_stage_info stage_rename; +extern PSI_stage_info stage_rename_result_table; +extern PSI_stage_info stage_requesting_binlog_dump; +extern PSI_stage_info stage_reschedule; +extern PSI_stage_info stage_searching_rows_for_update; +extern PSI_stage_info stage_sending_binlog_event_to_slave; +extern PSI_stage_info stage_sending_cached_result_to_client; +extern PSI_stage_info stage_sending_data; +extern PSI_stage_info stage_setup; +extern PSI_stage_info stage_slave_has_read_all_relay_log; +extern PSI_stage_info stage_show_explain; +extern PSI_stage_info stage_sorting; +extern PSI_stage_info stage_sorting_for_group; +extern PSI_stage_info stage_sorting_for_order; +extern PSI_stage_info stage_sorting_result; +extern PSI_stage_info stage_sql_thd_waiting_until_delay; +extern PSI_stage_info stage_statistics; +extern PSI_stage_info stage_storing_result_in_query_cache; +extern PSI_stage_info stage_storing_row_into_queue; +extern PSI_stage_info stage_system_lock; +extern PSI_stage_info stage_update; +extern PSI_stage_info stage_updating; +extern PSI_stage_info stage_updating_main_table; +extern PSI_stage_info stage_updating_reference_tables; +extern PSI_stage_info stage_upgrading_lock; +extern PSI_stage_info stage_user_lock; +extern PSI_stage_info stage_user_sleep; +extern PSI_stage_info stage_verifying_table; +extern PSI_stage_info stage_waiting_for_delay_list; +extern PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log; +extern PSI_stage_info stage_waiting_for_handler_insert; +extern PSI_stage_info stage_waiting_for_handler_lock; +extern PSI_stage_info stage_waiting_for_handler_open; +extern PSI_stage_info stage_waiting_for_insert; +extern PSI_stage_info stage_waiting_for_master_to_send_event; +extern PSI_stage_info stage_waiting_for_master_update; +extern PSI_stage_info stage_waiting_for_relay_log_space; +extern PSI_stage_info stage_waiting_for_slave_mutex_on_exit; +extern PSI_stage_info stage_waiting_for_slave_thread_to_start; +extern PSI_stage_info stage_waiting_for_query_cache_lock; +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_slave_waiting_worker_to_release_partition; +extern PSI_stage_info stage_slave_waiting_worker_to_free_events; +extern PSI_stage_info stage_slave_waiting_worker_queue; +extern PSI_stage_info stage_slave_waiting_event_from_coordinator; +extern PSI_stage_info stage_slave_waiting_workers_to_exit; +extern PSI_stage_info stage_binlog_waiting_background_tasks; +extern PSI_stage_info stage_binlog_processing_checkpoint_notify; +extern PSI_stage_info stage_binlog_stopping_background_thread; +#ifdef HAVE_PSI_STATEMENT_INTERFACE +/** + Statement instrumentation keys (sql). + The last entry, at [SQLCOM_END], is for parsing errors. +*/ +extern PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1]; + +/** + Statement instrumentation keys (com). + The last entry, at [COM_END], is for packet errors. +*/ +extern PSI_statement_info com_statement_info[(uint) COM_END + 1]; + +void init_sql_statement_info(); +void init_com_statement_info(); +#endif /* HAVE_PSI_STATEMENT_INTERFACE */ + #ifndef __WIN__ extern pthread_t signal_thread; #endif @@ -355,7 +486,7 @@ extern int32 thread_running; extern my_atomic_rwlock_t thread_running_lock; extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, - *opt_ssl_key; + *opt_ssl_key, *opt_ssl_crl, *opt_ssl_crlpath; extern MYSQL_PLUGIN_IMPORT pthread_key(THD*, THR_THD); @@ -390,7 +521,10 @@ enum options_mysqld OPT_LOG_ERROR, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_LONG_DATA_SIZE, + OPT_PLUGIN_LOAD, + OPT_PLUGIN_LOAD_ADD, OPT_ONE_THREAD, + OPT_PFS_INSTRUMENT, OPT_POOL_OF_THREADS, OPT_REPLICATE_DO_DB, OPT_REPLICATE_DO_TABLE, @@ -412,6 +546,8 @@ enum options_mysqld OPT_SSL_CAPATH, OPT_SSL_CERT, OPT_SSL_CIPHER, + OPT_SSL_CRL, + OPT_SSL_CRLPATH, OPT_SSL_KEY, OPT_UPDATE_LOG, OPT_WANT_CORE, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index cf3e962053c..b6890ab9fda 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2012, Monty Program Ab + Copyright (c) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @file @@ -112,11 +112,15 @@ extern void query_cache_insert(const char *packet, ulong length, #define update_statistics(A) #endif +#ifdef MYSQL_SERVER +/* Additional instrumentation hooks for the server */ +#include "mysql_com_server.h" +#endif + #define TEST_BLOCKING 8 #define MAX_PACKET_LENGTH (256L*256L*256L-1) -static my_bool net_write_buff(NET *net,const uchar *packet,ulong len); - +static my_bool net_write_buff(NET *, const uchar *, ulong); /** Init with packet info. */ @@ -141,10 +145,14 @@ my_bool my_net_init(NET *net, Vio* vio, uint my_flags) net->last_errno=0; net->unused= 0; net->thread_specific_malloc= test(my_flags & MY_THREAD_SPECIFIC); +#ifdef MYSQL_SERVER + net->extension= NULL; +#endif - if (vio != 0) /* If real connection */ + if (vio) { - net->fd = vio_fd(vio); /* For perl DBI/DBD */ + /* For perl DBI/DBD. */ + net->fd= vio_fd(vio); #if defined(MYSQL_SERVER) && !defined(__WIN__) if (!(test_flags & TEST_BLOCKING)) { @@ -266,7 +274,10 @@ static int net_data_is_ready(my_socket sd) #endif /* EMBEDDED_LIBRARY */ /** - Intialize NET handler for new reads: + Clear (reinitialize) the NET structure for a new command. + + @remark Performs debug checking of the socket buffer to + ensure that the protocol sequence is correct. - Read from socket until there is nothing more to read. Discard what is read. @@ -299,7 +310,7 @@ void net_clear(NET *net, my_bool clear_buffer __attribute__((unused))) { size_t count; int ready; - while ((ready= net_data_is_ready(net->vio->sd)) > 0) + while ((ready= net_data_is_ready(vio_fd(net->vio))) > 0) { /* The socket is ready */ if ((long) (count= vio_read(net->vio, net->buff, @@ -351,7 +362,7 @@ my_bool net_flush(NET *net) { error=test(net_real_write(net, net->buff, (size_t) (net->write_pos - net->buff))); - net->write_pos=net->buff; + net->write_pos= net->buff; } /* Sync packet number if using compression */ if (net->compress) @@ -367,15 +378,13 @@ my_bool net_flush(NET *net) /** Write a logical packet with packet header. - Format: Packet length (3 bytes), packet number(1 byte) - When compression is used a 3 byte compression length is added + Format: Packet length (3 bytes), packet number (1 byte) + When compression is used, a 3 byte compression length is added. - @note - If compression is used the original package is modified! + @note If compression is used, the original packet is modified! */ -my_bool -my_net_write(NET *net,const uchar *packet,size_t len) +my_bool my_net_write(NET *net, const uchar *packet, size_t len) { uchar buff[NET_HEADER_SIZE]; int rc; @@ -420,6 +429,7 @@ my_net_write(NET *net,const uchar *packet,size_t len) return rc; } + /** Send a command to the server. @@ -827,6 +837,19 @@ my_real_read(NET *net, size_t *complen) my_bool net_blocking=vio_is_blocking(net->vio); uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE : NET_HEADER_SIZE); +#ifdef MYSQL_SERVER + size_t count= remain; + struct st_net_server *server_extension; + server_extension= static_cast<st_net_server*> (net->extension); + if (server_extension != NULL) + { + void *user_data= server_extension->m_user_data; + DBUG_ASSERT(server_extension->m_before_header != NULL); + DBUG_ASSERT(server_extension->m_after_header != NULL); + server_extension->m_before_header(net, user_data, count); + } +#endif + *complen = 0; net->reading_or_writing=1; @@ -902,7 +925,7 @@ my_real_read(NET *net, size_t *complen) remain, vio_errno(net->vio), (long) length)); len= packet_error; net->error= 2; /* Close socket */ - net->last_errno= (vio_was_interrupted(net->vio) ? + net->last_errno= (vio_was_timeout(net->vio) ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); MYSQL_SERVER_my_error(net->last_errno, MYF(0)); @@ -983,6 +1006,14 @@ my_real_read(NET *net, size_t *complen) } pos=net->buff + net->where_b; remain = (uint32) len; +#ifdef MYSQL_SERVER + if (server_extension != NULL) + { + void *user_data= server_extension->m_user_data; + server_extension->m_after_header(net, user_data, count, 0); + server_extension= NULL; + } +#endif } } @@ -999,6 +1030,14 @@ end: if (len != packet_error) DBUG_DUMP("data", net->buff+net->where_b, len); #endif +#ifdef MYSQL_SERVER + if (server_extension != NULL) + { + void *user_data= server_extension->m_user_data; + server_extension->m_after_header(net, user_data, count, 1); + DBUG_ASSERT(len == packet_error || len == 0); + } +#endif return(len); } @@ -1167,13 +1206,12 @@ void my_net_set_read_timeout(NET *net, uint timeout) { DBUG_ENTER("my_net_set_read_timeout"); DBUG_PRINT("enter", ("timeout: %d", timeout)); - if (net->read_timeout == timeout) - DBUG_VOID_RETURN; - net->read_timeout= timeout; -#ifdef NO_ALARM - if (net->vio) - vio_timeout(net->vio, 0, timeout); -#endif + if (net->read_timeout != timeout) + { + net->read_timeout= timeout; + if (net->vio) + vio_timeout(net->vio, 0, timeout); + } DBUG_VOID_RETURN; } @@ -1182,12 +1220,11 @@ void my_net_set_write_timeout(NET *net, uint timeout) { DBUG_ENTER("my_net_set_write_timeout"); DBUG_PRINT("enter", ("timeout: %d", timeout)); - if (net->write_timeout == timeout) - DBUG_VOID_RETURN; - net->write_timeout= timeout; -#ifdef NO_ALARM - if (net->vio) - vio_timeout(net->vio, 1, timeout); -#endif + if (net->write_timeout != timeout) + { + net->write_timeout= timeout; + if (net->vio) + vio_timeout(net->vio, 1, timeout); + } DBUG_VOID_RETURN; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7a3a0c94a18..2205d2fcab4 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -891,7 +891,7 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts); static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, SEL_ARG *tree, bool update_tbl_stats, uint *mrr_flags, uint *bufsize, - COST_VECT *cost); + Cost_estimate *cost); QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, SEL_ARG *key_tree, uint mrr_flags, @@ -6730,7 +6730,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, if (*key) { ha_rows found_records; - COST_VECT cost; + Cost_estimate cost; double found_read_time; uint mrr_flags, buf_size; INDEX_SCAN_INFO *index_scan; @@ -9980,7 +9980,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root) static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, SEL_ARG *tree, bool update_tbl_stats, - uint *mrr_flags, uint *bufsize, COST_VECT *cost) + uint *mrr_flags, uint *bufsize, Cost_estimate *cost) { SEL_ARG_RANGE_SEQ seq; RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0}; @@ -10469,7 +10469,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, QUICK_RANGE *range; uint part; bool create_err= FALSE; - COST_VECT cost; + Cost_estimate cost; old_root= thd->mem_root; /* The following call may change thd->mem_root */ @@ -11002,9 +11002,6 @@ int QUICK_RANGE_SELECT::reset() last_range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer; RANGE_SEQ_IF seq_funcs= {NULL, quick_range_seq_init, quick_range_seq_next, 0, 0}; - - if (in_ror_merged_scan) - head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); if (file->inited == handler::RND) { @@ -11013,6 +11010,9 @@ int QUICK_RANGE_SELECT::reset() DBUG_RETURN(error); } + if (in_ror_merged_scan) + head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); + if (file->inited == handler::NONE) { DBUG_EXECUTE_IF("bug14365043_2", @@ -12200,7 +12200,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) cur_index_tree= get_index_range_tree(cur_index, tree, param, &cur_param_idx); /* Check if this range tree can be used for prefix retrieval. */ - COST_VECT dummy_cost; + Cost_estimate dummy_cost; uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL; uint mrr_bufsize=0; cur_quick_prefix_records= check_quick_select(param, cur_param_idx, diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index e149de6fe53..8cd4ba08ff3 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2200,7 +2200,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) Set the cost to do a full scan of the temptable (will need this to consider doing sjm-scan): */ - sjm->scan_cost.zero(); + sjm->scan_cost.reset(); sjm->scan_cost.add_io(sjm->rows, lookup_cost); sjm->lookup_cost.convert_from_cost(lookup_cost); @@ -2635,12 +2635,12 @@ bool Sj_materialization_picker::check_qep(JOIN *join, else { /* This is SJ-Materialization with lookups */ - COST_VECT prefix_cost; + Cost_estimate prefix_cost; signed int first_tab= (int)idx - mat_info->tables; double prefix_rec_count; if (first_tab < (int)join->const_tables) { - prefix_cost.zero(); + prefix_cost.reset(); prefix_rec_count= 1.0; } else @@ -3851,7 +3851,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) /* STEP 1: Get temporary table name */ - statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status); + thd->inc_status_created_tmp_tables(); if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) temp_pool_slot = bitmap_lock_set_next(&temp_pool); diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 7b8f3142851..007ce2e6d15 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -371,8 +371,8 @@ public: These are the members we got from temptable creation code. We'll need them if we'll need to convert table from HEAP to MyISAM/Maria. */ - ENGINE_COLUMNDEF *start_recinfo; - ENGINE_COLUMNDEF *recinfo; + TMP_ENGINE_COLUMNDEF *start_recinfo; + TMP_ENGINE_COLUMNDEF *recinfo; SJ_TMP_TABLE *next_flush_table; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 89fb1bb27de..86f19f1b28e 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -43,7 +43,6 @@ ulong rpl_status=RPL_NULL; mysql_mutex_t LOCK_rpl_status; -mysql_cond_t COND_rpl_status; HASH slave_list; const char *rpl_role_type[] = {"MASTER","SLAVE",NullS}; @@ -69,7 +68,6 @@ void change_rpl_status(ulong from_status, ulong to_status) mysql_mutex_lock(&LOCK_rpl_status); if (rpl_status == from_status || rpl_status == RPL_ANY) rpl_status = to_status; - mysql_cond_signal(&COND_rpl_status); mysql_mutex_unlock(&LOCK_rpl_status); } diff --git a/sql/replication.h b/sql/replication.h index 8027c4830ec..510e56a3085 100644 --- a/sql/replication.h +++ b/sql/replication.h @@ -10,8 +10,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef REPLICATION_H #define REPLICATION_H @@ -460,34 +460,6 @@ int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void MYSQL *rpl_connect_master(MYSQL *mysql); /** - Set thread entering a condition - - This function should be called before putting a thread to wait for - a condition. @a mutex should be held before calling this - function. After being waken up, @f thd_exit_cond should be called. - - @param thd The thread entering the condition, NULL means current thread - @param cond The condition the thread is going to wait for - @param mutex The mutex associated with the condition, this must be - held before call this function - @param msg The new process message for the thread -*/ -const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, - mysql_mutex_t *mutex, const char *msg); - -/** - Set thread leaving a condition - - This function should be called after a thread being waken up for a - condition. - - @param thd The thread entering the condition, NULL means current thread - @param old_msg The process message, ususally this should be the old process - message before calling @f thd_enter_cond -*/ -void thd_exit_cond(MYSQL_THD thd, const char *old_msg); - -/** Get the value of user variable as an integer. This function will return the value of variable @a name as an diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 5348a94b35b..3e02b555dc0 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -42,6 +42,7 @@ Master_info::Master_info(LEX_STRING *connection_name_arg, host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; ssl_cipher[0]= 0; ssl_key[0]= 0; + ssl_crl[0]= 0; ssl_crlpath[0]= 0; /* Store connection name and lower case connection name @@ -164,14 +165,30 @@ enum { /* 5.1.16 added value of master_ssl_verify_server_cert */ LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15, - /* 6.0 added value of master_heartbeat_period */ + + /* 5.5 added value of master_heartbeat_period */ LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16, + /* MySQL Cluster 6.3 added master_bind */ LINE_FOR_MASTER_BIND = 17, + /* 6.0 added value of master_ignore_server_id */ LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18, + + /* 6.0 added value of master_uuid */ + LINE_FOR_MASTER_UUID= 19, + + /* line for master_retry_count */ + LINE_FOR_MASTER_RETRY_COUNT= 20, + + /* line for ssl_crl */ + LINE_FOR_SSL_CRL= 21, + + /* line for ssl_crl */ + LINE_FOR_SSL_CRLPATH= 22, + /* Number of lines currently used when saving master info file */ - LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS + LINES_IN_MASTER_INFO= LINE_FOR_SSL_CRLPATH }; int init_master_info(Master_info* mi, const char* master_info_fname, @@ -405,6 +422,23 @@ file '%s')", fname); sql_print_error("Failed to initialize master info ignore_server_ids"); goto errwithmsg; } + + /* reserved */ + if (lines >= LINE_FOR_MASTER_UUID && + init_strvar_from_file(dummy_buf, sizeof(dummy_buf), &mi->file, "")) + goto errwithmsg; + + /* Starting from 5.5 the master_retry_count may be in the repository. */ + if (lines >= LINE_FOR_MASTER_RETRY_COUNT && + init_strvar_from_file(dummy_buf, sizeof(dummy_buf), &mi->file, "")) + goto errwithmsg; + + if (lines >= LINE_FOR_SSL_CRLPATH && + (init_strvar_from_file(mi->ssl_crl, sizeof(mi->ssl_crl), + &mi->file, "") || + init_strvar_from_file(mi->ssl_crlpath, sizeof(mi->ssl_crlpath), + &mi->file, ""))) + goto errwithmsg; } #ifndef HAVE_OPENSSL @@ -544,14 +578,16 @@ int flush_master_info(Master_info* mi, sprintf(heartbeat_buf, "%.3f", mi->heartbeat_period); my_b_seek(file, 0L); my_b_printf(file, - "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n", + "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n", LINES_IN_MASTER_INFO, mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert, - heartbeat_buf, "", ignore_server_ids_buf); + heartbeat_buf, "", ignore_server_ids_buf, + "", 0, + mi->ssl_crl, mi->ssl_crlpath); my_free(ignore_server_ids_buf); err= flush_io_cache(file); if (sync_masterinfo_period && !err && diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index d52b2992afd..108bd51ff47 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -79,6 +79,7 @@ class Master_info : public Slave_reporting_capability bool ssl; // enables use of SSL connection if true char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; + char ssl_crl[FN_REFLEN], ssl_crlpath[FN_REFLEN]; bool ssl_verify_server_cert; my_off_t master_log_pos; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index d5cd6a3efed..2e74acc0345 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2006, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -10,8 +11,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include "sql_priv.h" #include "unireg.h" // HAVE_* @@ -696,7 +697,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name, ulong init_abort_pos_wait; int error=0; struct timespec abstime; // for timeout checking - const char *msg; + PSI_stage_info old_stage; DBUG_ENTER("Relay_log_info::wait_for_pos"); if (!inited) @@ -707,9 +708,9 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name, set_timespec(abstime,timeout); mysql_mutex_lock(&data_lock); - msg= thd->enter_cond(&data_cond, &data_lock, - "Waiting for the slave SQL thread to " - "advance position"); + thd->ENTER_COND(&data_cond, &data_lock, + &stage_waiting_for_the_slave_thread_to_advance_position, + &old_stage); /* This function will abort when it notices that some CHANGE MASTER or RESET MASTER has changed the master info. @@ -853,7 +854,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name, } err: - thd->exit_cond(msg); + thd->EXIT_COND(&old_stage); DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \ improper_arguments: %d timed_out: %d", thd->killed_errno(), diff --git a/sql/set_var.cc b/sql/set_var.cc index 2d3e0b7fec4..9f5404d75ce 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. - Copyright (c) 2008-2011 Monty Program Ab + Copyright (c) 2008, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation -#endif - /* variable declarations are in sys_vars.cc now !!! */ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -315,7 +311,7 @@ bool throw_bounds_warning(THD *thd, const char *name, else llstr(v, buf); - if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) + if (thd->is_strict_mode()) { my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf); return true; @@ -335,7 +331,7 @@ bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v) my_gcvt(v, MY_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL); - if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) + if (thd->is_strict_mode()) { my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf); return true; @@ -531,6 +527,7 @@ sys_var *intern_find_sys_var(const char *str, uint length) */ var= (sys_var*) my_hash_search(&system_variable_hash, (uchar*) str, length ? length : strlen(str)); + return var; } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index a6ebebeae39..49f35719a77 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -3288,45 +3288,45 @@ ER_NONEXISTING_GRANT 42000 swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'" ukr "Повноважень не визначено для користувача '%-.48s' з хосту '%-.64s'" ER_TABLEACCESS_DENIED_ERROR 42000 - cze "%-.32s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro tabulku '%-.192s'" - dan "%-.32s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for tabellen '%-.192s'" - nla "%-.32s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor tabel '%-.192s'" - eng "%-.32s command denied to user '%-.48s'@'%-.64s' for table '%-.192s'" - jps "コマンド %-.32s は ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' に対して許可されていません", - est "%-.32s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tabelis '%-.192s'" - fre "La commande '%-.32s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la table '%-.192s'" - ger "%-.32s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' auf Tabelle '%-.192s'" - hun "%-.32s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban" - ita "Comando %-.32s negato per l'utente: '%-.48s'@'%-.64s' sulla tabella '%-.192s'" - jpn "コマンド %-.32s は ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' に対して許可されていません" - kor "'%-.32s' 명령은 다음 사용자에게 거부되었습니다. : '%-.48s'@'%-.64s' for 테이블 '%-.192s'" - por "Comando '%-.32s' negado para o usuário '%-.48s'@'%-.64s' na tabela '%-.192s'" - rum "Comanda %-.32s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru tabela '%-.192s'" - rus "Команда %-.32s запрещена пользователю '%-.48s'@'%-.64s' для таблицы '%-.192s'" - serbian "%-.32s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za tabelu '%-.192s'" - spa "%-.32s comando negado para usuario: '%-.48s'@'%-.64s' para tabla '%-.192s'" - swe "%-.32s ej tillåtet för '%-.48s'@'%-.64s' för tabell '%-.192s'" - ukr "%-.32s команда заборонена користувачу: '%-.48s'@'%-.64s' у таблиці '%-.192s'" + cze "%-.128s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro tabulku '%-.192s'" + dan "%-.128s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for tabellen '%-.192s'" + nla "%-.128s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor tabel '%-.192s'" + eng "%-.128s command denied to user '%-.48s'@'%-.64s' for table '%-.192s'" + jps "コマンド %-.128s は ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' に対して許可されていません", + est "%-.128s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tabelis '%-.192s'" + fre "La commande '%-.128s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la table '%-.192s'" + ger "%-.128s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' auf Tabelle '%-.192s'" + hun "%-.128s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban" + ita "Comando %-.128s negato per l'utente: '%-.48s'@'%-.64s' sulla tabella '%-.192s'" + jpn "コマンド %-.128s は ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' に対して許可されていません" + kor "'%-.128s' 명령은 다음 사용자에게 거부되었습니다. : '%-.48s'@'%-.64s' for 테이블 '%-.192s'" + por "Comando '%-.128s' negado para o usuário '%-.48s'@'%-.64s' na tabela '%-.192s'" + rum "Comanda %-.128s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru tabela '%-.192s'" + rus "Команда %-.128s запрещена пользователю '%-.48s'@'%-.64s' для таблицы '%-.192s'" + serbian "%-.128s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za tabelu '%-.192s'" + spa "%-.128s comando negado para usuario: '%-.48s'@'%-.64s' para tabla '%-.192s'" + swe "%-.128s ej tillåtet för '%-.48s'@'%-.64s' för tabell '%-.192s'" + ukr "%-.128s команда заборонена користувачу: '%-.48s'@'%-.64s' у таблиці '%-.192s'" ER_COLUMNACCESS_DENIED_ERROR 42000 - cze "%-.32s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro sloupec '%-.192s' v tabulce '%-.192s'" - dan "%-.32s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for kolonne '%-.192s' in tabellen '%-.192s'" - nla "%-.32s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor kolom '%-.192s' in tabel '%-.192s'" - eng "%-.32s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'" - jps "コマンド %-.32s は ユーザー '%-.48s'@'%-.64s'¥n カラム '%-.192s' テーブル '%-.192s' に対して許可されていません", - est "%-.32s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tulbale '%-.192s' tabelis '%-.192s'" - fre "La commande '%-.32s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la colonne '%-.192s' de la table '%-.192s'" - ger "%-.32s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' und Feld '%-.192s' in Tabelle '%-.192s'" - hun "%-.32s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' mezo eseten a '%-.192s' tablaban" - ita "Comando %-.32s negato per l'utente: '%-.48s'@'%-.64s' sulla colonna '%-.192s' della tabella '%-.192s'" - jpn "コマンド %-.32s は ユーザー '%-.48s'@'%-.64s'\n カラム '%-.192s' テーブル '%-.192s' に対して許可されていません" - kor "'%-.32s' 명령은 다음 사용자에게 거부되었습니다. : '%-.48s'@'%-.64s' for 칼럼 '%-.192s' in 테이블 '%-.192s'" - por "Comando '%-.32s' negado para o usuário '%-.48s'@'%-.64s' na coluna '%-.192s', na tabela '%-.192s'" - rum "Comanda %-.32s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru coloana '%-.192s' in tabela '%-.192s'" - rus "Команда %-.32s запрещена пользователю '%-.48s'@'%-.64s' для столбца '%-.192s' в таблице '%-.192s'" - serbian "%-.32s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za kolonu '%-.192s' iz tabele '%-.192s'" - spa "%-.32s comando negado para usuario: '%-.48s'@'%-.64s' para columna '%-.192s' en la tabla '%-.192s'" - swe "%-.32s ej tillåtet för '%-.48s'@'%-.64s' för kolumn '%-.192s' i tabell '%-.192s'" - ukr "%-.32s команда заборонена користувачу: '%-.48s'@'%-.64s' для стовбця '%-.192s' у таблиці '%-.192s'" + cze "%-.128s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro sloupec '%-.192s' v tabulce '%-.192s'" + dan "%-.128s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for kolonne '%-.192s' in tabellen '%-.192s'" + nla "%-.128s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor kolom '%-.192s' in tabel '%-.192s'" + eng "%-.128s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'" + jps "コマンド %-.128s は ユーザー '%-.48s'@'%-.64s'¥n カラム '%-.192s' テーブル '%-.192s' に対して許可されていません", + est "%-.128s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tulbale '%-.192s' tabelis '%-.192s'" + fre "La commande '%-.128s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la colonne '%-.192s' de la table '%-.192s'" + ger "%-.128s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' und Feld '%-.192s' in Tabelle '%-.192s'" + hun "%-.128s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' mezo eseten a '%-.192s' tablaban" + ita "Comando %-.128s negato per l'utente: '%-.48s'@'%-.64s' sulla colonna '%-.192s' della tabella '%-.192s'" + jpn "コマンド %-.128s は ユーザー '%-.48s'@'%-.64s'\n カラム '%-.192s' テーブル '%-.192s' に対して許可されていません" + kor "'%-.128s' 명령은 다음 사용자에게 거부되었습니다. : '%-.48s'@'%-.64s' for 칼럼 '%-.192s' in 테이블 '%-.192s'" + por "Comando '%-.128s' negado para o usuário '%-.48s'@'%-.64s' na coluna '%-.192s', na tabela '%-.192s'" + rum "Comanda %-.128s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru coloana '%-.192s' in tabela '%-.192s'" + rus "Команда %-.128s запрещена пользователю '%-.48s'@'%-.64s' для столбца '%-.192s' в таблице '%-.192s'" + serbian "%-.128s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za kolonu '%-.192s' iz tabele '%-.192s'" + spa "%-.128s comando negado para usuario: '%-.48s'@'%-.64s' para columna '%-.192s' en la tabla '%-.192s'" + swe "%-.128s ej tillåtet för '%-.48s'@'%-.64s' för kolumn '%-.192s' i tabell '%-.192s'" + ukr "%-.128s команда заборонена користувачу: '%-.48s'@'%-.64s' для стовбця '%-.192s' у таблиці '%-.192s'" ER_ILLEGAL_GRANT_FOR_TABLE 42000 cze "Neplatn-Bý příkaz GRANT/REVOKE. Prosím, přečtěte si v manuálu, jaká privilegia je možné použít." dan "Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres." @@ -5330,8 +5330,8 @@ ER_VIEW_CHECK_FAILED rus "проверка CHECK OPTION для VIEW '%-.192s.%-.192s' провалилась" ukr "Перевірка CHECK OPTION для VIEW '%-.192s.%-.192s' не пройшла" ER_PROCACCESS_DENIED_ERROR 42000 - eng "%-.32s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'" - ger "Befehl %-.32s nicht zulässig für Benutzer '%-.48s'@'%-.64s' in Routine '%-.192s'" + eng "%-.128s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'" + ger "Befehl %-.128s nicht zulässig für Benutzer '%-.48s'@'%-.64s' in Routine '%-.192s'" ER_RELAY_LOG_FAIL eng "Failed purging old relay logs: %s" ger "Bereinigen alter Relais-Logs fehlgeschlagen: %s" @@ -5912,10 +5912,12 @@ ER_EVENT_OPEN_TABLE_FAILED ER_EVENT_NEITHER_M_EXPR_NOR_M_AT eng "No datetime expression provided" ger "Kein DATETIME-Ausdruck angegeben" -ER_COL_COUNT_DOESNT_MATCH_CORRUPTED + +ER_UNUSED_2 eng "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted" ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt" -ER_CANNOT_LOAD_FROM_TABLE + +ER_UNUSED_3 eng "Cannot load from mysql.%s. The table is probably corrupted" ger "Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt" ER_EVENT_CANNOT_DELETE @@ -5944,7 +5946,7 @@ ER_CANT_WRITE_LOCK_LOG_TABLE ER_CANT_LOCK_LOG_TABLE eng "You can't use locks with log tables." ger "Log-Tabellen können nicht gesperrt werden." -ER_FOREIGN_DUPLICATE_KEY 23000 S1009 +ER_UNUSED_4 eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry" ger "Aufrechterhalten der Fremdschlüssel-Beschränkungen für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen" ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE @@ -5981,9 +5983,8 @@ ER_WRONG_PARTITION_NAME eng "Incorrect partition name" ger "Falscher Partitionsname" swe "Felaktigt partitionsnamn" -ER_CANT_CHANGE_TX_ISOLATION 25001 - eng "Transaction isolation level can't be changed while a transaction is in progress" - ger "Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden" +ER_CANT_CHANGE_TX_CHARACTERISTICS 25001 + eng "Transaction characteristics can't be changed while a transaction is in progress" ER_DUP_ENTRY_AUTOINCREMENT_CASE eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'" ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.192s' für Schlüssel '%-.192s' auftritt" @@ -6071,8 +6072,8 @@ ER_EVENT_CANNOT_CREATE_IN_THE_PAST eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." ger "Ausführungszeit des Events liegt in der Vergangenheit, und es wurde ON COMPLETION NOT PRESERVE gesetzt. Das Event wurde unmittelbar nach Erzeugung gelöscht." ER_EVENT_CANNOT_ALTER_IN_THE_PAST - eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." - ger "Ausführungszeit des Events liegt in der Vergangenheit, und es wurde ON COMPLETION NOT PRESERVE gesetzt. Das Event wurde unmittelbar nach Erzeugung gelöscht." + eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was not changed. Specify a time in the future." + ger "Execution Zeitpunkt des Ereignisses in der Vergangenheit liegt, und es war NACH ABSCHLUSS Set nicht erhalten. Die Veranstaltung wurde nicht verändert. Geben Sie einen Zeitpunkt in der Zukunft." ER_SLAVE_INCIDENT eng "The incident %s occured on the master. Message: %-.64s" ger "Der Vorfall %s passierte auf dem Master. Meldung: %-.64s" @@ -6486,6 +6487,7 @@ ER_PLUGIN_NO_UNINSTALL ER_PLUGIN_NO_INSTALL eng "Plugin '%s' is marked as not dynamically installable. You have to stop the server to install it." + ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT eng "Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave." @@ -6508,6 +6510,226 @@ ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST # End of 5.5 error messages. # +ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 + eng "Column count of %s.%s is wrong. Expected %d, found %d. The table is probably corrupted" + ger "Spaltenanzahl von %s.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt" + +ER_CANNOT_LOAD_FROM_TABLE_V2 + eng "Cannot load from %s.%s. The table is probably corrupted" + ger "Kann %s.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt" + + +ER_MASTER_DELAY_VALUE_OUT_OF_RANGE + eng "The requested value %u for the master delay exceeds the maximum %u" +ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT + eng "Only Format_description_log_event and row events are allowed in BINLOG statements (but %s was provided)" + +ER_PARTITION_EXCHANGE_DIFFERENT_OPTION + eng "Non matching attribute '%-.64s' between partition and table" + swe "Attributet '%-.64s' är olika mellan partition och tabell" +ER_PARTITION_EXCHANGE_PART_TABLE + eng "Table to exchange with partition is partitioned: '%-.64s'" + swe "Tabellen att byta ut mot partition är partitionerad: '%-.64s'" +ER_PARTITION_EXCHANGE_TEMP_TABLE + eng "Table to exchange with partition is temporary: '%-.64s'" + swe "Tabellen att byta ut mot partition är temporär: '%-.64s'" +ER_PARTITION_INSTEAD_OF_SUBPARTITION + eng "Subpartitioned table, use subpartition instead of partition" + swe "Subpartitionerad tabell, använd subpartition istället för partition" +ER_UNKNOWN_PARTITION + eng "Unknown partition '%-.64s' in table '%-.64s'" + swe "Okänd partition '%-.64s' i tabell '%-.64s'" +ER_TABLES_DIFFERENT_METADATA + eng "Tables have different definitions" + swe "Tabellerna har olika definitioner" +ER_ROW_DOES_NOT_MATCH_PARTITION + eng "Found a row that does not match the partition" + swe "Hittade en rad som inte passar i partitionen" +ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX + eng "Option binlog_cache_size (%lu) is greater than max_binlog_cache_size (%lu); setting binlog_cache_size equal to max_binlog_cache_size." +ER_WARN_INDEX_NOT_APPLICABLE + eng "Cannot use %-.64s access on index '%-.64s' due to type or collation conversion on field '%-.64s'" + +ER_PARTITION_EXCHANGE_FOREIGN_KEY + eng "Table to exchange with partition has foreign key references: '%-.64s'" + swe "Tabellen att byta ut mot partition har foreign key referenser: '%-.64s'" +ER_NO_SUCH_KEY_VALUE + eng "Key value '%-.192s' was not found in table '%-.192s.%-.192s'" +ER_RPL_INFO_DATA_TOO_LONG + eng "Data for column '%s' too long" +ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE + eng "Replication event checksum verification failed while reading from network." +ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE + eng "Replication event checksum verification failed while reading from a log file." + +ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX + eng "Option binlog_stmt_cache_size (%lu) is greater than max_binlog_stmt_cache_size (%lu); setting binlog_stmt_cache_size equal to max_binlog_stmt_cache_size." +ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT + eng "Can't update table '%-.192s' while '%-.192s' is being created." + +ER_PARTITION_CLAUSE_ON_NONPARTITIONED + eng "PARTITION () clause on non partitioned table" + swe "PARTITION () klausul för en icke partitionerad tabell" +ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET + eng "Found a row not matching the given partition set" + swe "Hittade en rad som inte passar i någon given partition" +ER_NO_SUCH_PARTITION + cze "partion '%-.64s' neexistuje" + dan "partition '%-.64s' eksisterer ikke" + nla "partition '%-.64s' bestaat niet" + eng "partition '%-.64s' doesn't exist" + est "partition '%-.64s' ei eksisteeri" + fre "La partition '%-.64s' n'existe pas" + ger "Die partition '%-.64s' existiert nicht" + hun "A '%-.64s' partition nem letezik" + ita "La tabella particione '%-.64s' non esiste" + nor "Partition '%-.64s' doesn't exist" + norwegian-ny "Partition '%-.64s' doesn't exist" + pol "Partition '%-.64s' doesn't exist" + por "Particion '%-.64s' n�o existe" + rum "Partition '%-.64s' nu exista" + serbian "Partition '%-.64s' ne postoji" + slo "Partition '%-.64s' doesn't exist" + spa "Particion '%-.64s' no existe" + swe "Det finns ingen partition som heter '%-.64s'" + +ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE + eng "Failure while changing the type of replication repository: %s." + +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE + eng "The creation of some temporary tables could not be rolled back." +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE + eng "Some temporary tables were dropped, but these operations could not be rolled back." + +ER_MTS_FEATURE_IS_NOT_SUPPORTED + eng "%s is not supported in multi-threaded slave mode. %s" +ER_MTS_UPDATED_DBS_GREATER_MAX + eng "The number of modified databases exceeds the maximum %d; the database names will not be included in the replication event metadata." +ER_MTS_CANT_PARALLEL + eng "Cannot execute the current event group in the parallel mode. Encountered event %s, relay-log name %s, position %s which prevents execution of this event group in parallel mode. Reason: %s." +ER_MTS_INCONSISTENT_DATA + eng "%s" + +ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING + eng "FULLTEXT index is not supported for partitioned tables." + swe "FULLTEXT index stöds ej för partitionerade tabeller." + +ER_DA_INVALID_CONDITION_NUMBER 35000 + eng "Invalid condition number" + por "Número de condição inválido" + +ER_INSECURE_PLAIN_TEXT + eng "Sending passwords in plain text without SSL/TLS is extremely insecure." + +ER_INSECURE_CHANGE_MASTER + eng "Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives." + +ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO 23000 S1009 + eng "Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in table '%.192s', key '%.192s'" + ger "Fremdschlüssel-Beschränkung für Tabelle '%.192s', Datensatz '%-.192s' würde zu einem doppelten Eintrag in Tabelle '%.192s', Schlüssel '%.192s' führen" + swe "FOREIGN KEY constraint för tabell '%.192s', posten '%-.192s' kan inte uppdatera barntabell '%.192s' på grund av nyckel '%.192s'" + +ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO 23000 S1009 + eng "Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in a child table" + ger "Fremdschlüssel-Beschränkung für Tabelle '%.192s', Datensatz '%-.192s' würde zu einem doppelten Eintrag in einer Kind-Tabelle führen" + swe "FOREIGN KEY constraint för tabell '%.192s', posten '%-.192s' kan inte uppdatera en barntabell på grund av UNIQUE-test" +ER_SQLTHREAD_WITH_SECURE_SLAVE + eng "Setting authentication options is not possible when only the Slave SQL Thread is being started." + +ER_TABLE_HAS_NO_FT + eng "The table does not have FULLTEXT index to support this query" + +ER_INNODB_FT_LIMIT + eng "InnoDB presently supports one FULLTEXT index per table" + +ER_INNODB_NO_FT_TEMP_TABLE + eng "Cannot create FULLTEXT index on temporary InnoDB table" + +ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER + eng "The system variable %.200s cannot be set in stored functions or triggers." + +ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION + eng "The system variable %.200s cannot be set when there is an ongoing transaction." + +ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST + eng "The system variable @@SESSION.GTID_NEXT has the value %.200s, which is not listed in @@SESSION.GTID_NEXT_LIST." + +ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL + eng "When @@SESSION.GTID_NEXT_LIST == NULL, the system variable @@SESSION.GTID_NEXT cannot change inside a transaction." + +ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION + eng "The statement 'SET %.200s' cannot invoke a stored function." + +ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL + eng "The system variable @@SESSION.GTID_NEXT cannot be 'AUTOMATIC' when @@SESSION.GTID_NEXT_LIST is non-NULL." + +ER_SKIPPING_LOGGED_TRANSACTION + eng "Skipping transaction %.200s because it has already been executed and logged." + +ER_MALFORMED_GTID_SET_SPECIFICATION + eng "Malformed GTID set specification '%.200s'." + +ER_MALFORMED_GTID_SET_ENCODING + eng "Malformed GTID set encoding." + +ER_MALFORMED_GTID_SPECIFICATION + eng "Malformed GTID specification '%.200s'." + +ER_GNO_EXHAUSTED + eng "Impossible to generate Global Transaction Identifier: the integer component reached the maximal value. Restart the server with a new server_uuid." + +ER_BAD_SLAVE_AUTO_POSITION + eng "Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active." + +ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON + eng "CHANGE MASTER TO AUTO_POSITION = 1 can only be executed when GTID_MODE = ON." + +ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET + eng "Cannot execute statements with implicit commit inside a transaction when GTID_NEXT != AUTOMATIC or GTID_NEXT_LIST != NULL." + +ER_GTID_MODE_2_OR_3_REQUIRES_DISABLE_GTID_UNSAFE_STATEMENTS_ON + eng "GTID_MODE = ON or GTID_MODE = UPGRADE_STEP_2 requires DISABLE_GTID_UNSAFE_STATEMENTS = 1." + +ER_GTID_MODE_REQUIRES_BINLOG + eng "GTID_MODE = ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates." + +ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF + eng "GTID_NEXT cannot be set to UUID:NUMBER when GTID_MODE = OFF." + +ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON + eng "GTID_NEXT cannot be set to ANONYMOUS when GTID_MODE = ON." + +ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF + eng "GTID_NEXT_LIST cannot be set to a non-NULL value when GTID_MODE = OFF." + +ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF + eng "Found a Gtid_log_event or Previous_gtids_log_event when GTID_MODE = OFF." + +ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE + eng "Updates to non-transactional tables are forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1." + +ER_GTID_UNSAFE_CREATE_SELECT + eng "CREATE TABLE ... SELECT is forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1." + +ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION + eng "When DISABLE_GTID_UNSAFE_STATEMENTS = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1." + +ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME + eng "The value of GTID_MODE can only change one step at a time: OFF <-> UPGRADE_STEP_1 <-> UPGRADE_STEP_2 <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for instructions." + +ER_MASTER_HAS_PURGED_REQUIRED_GTIDS + eng "The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires." + +ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID + eng "GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released on COMMIT or ROLLBACK." + +ER_UNKNOWN_EXPLAIN_FORMAT + eng "Unknown EXPLAIN format name: '%s'" + rus "Неизвестное имя формата команды EXPLAIN: '%s'" + +ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 25006 + eng "Cannot execute statement in a READ ONLY transaction." + # # MariaDB error messages section starts here # @@ -6547,10 +6769,10 @@ ER_UNKNOWN_OPTION eng "Unknown option '%-.64s'" ER_BAD_OPTION_VALUE eng "Incorrect value '%-.64s' for option '%-.64s'" -ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE - eng "Replication event checksum verification failed while reading from network." -ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE - eng "Replication event checksum verification failed while reading from a log file." +ER_NOT_USED_ERROR_MESSAGE + eng "" +ER_NOT_USED_ERROR_MESSAGE2 + eng "" ER_CANT_DO_ONLINE eng "Can't execute the given '%s' command as online" ER_DATA_OVERFLOW 22003 diff --git a/sql/slave.cc b/sql/slave.cc index da10169d97b..78fa7998012 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -507,7 +507,19 @@ static void set_thd_in_use_temporary_tables(Relay_log_info *rli) TABLE *table; for (table= rli->save_temporary_tables ; table ; table= table->next) + { table->in_use= rli->sql_thd; + if (table->file != NULL) + { + /* + Since we are stealing opened temporary tables from one thread to another, + we need to let the performance schema know that, + for aggregates per thread to work properly. + */ + table->file->unbind_psi(); + table->file->rebind_psi(); + } + } } int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) @@ -535,7 +547,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) DBUG_PRINT("info",("Flushing relay-log info file.")); if (current_thd) - thd_proc_info(current_thd, "Flushing relay-log info file."); + THD_STAGE_INFO(current_thd, stage_flushing_relay_log_info_file); if (flush_relay_log_info(&mi->rli)) DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS); @@ -559,7 +571,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) DBUG_PRINT("info",("Flushing relay log and master info file.")); if (current_thd) - thd_proc_info(current_thd, "Flushing relay log and master info files."); + THD_STAGE_INFO(current_thd, stage_flushing_relay_log_and_master_info_repository); if (flush_master_info(mi, TRUE, FALSE)) DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS); @@ -739,8 +751,10 @@ int start_slave_thread( while (start_id == *slave_run_id) { DBUG_PRINT("sleep",("Waiting for slave thread to start")); - const char *old_msg= thd->enter_cond(start_cond, cond_lock, - "Waiting for slave thread to start"); + PSI_stage_info saved_stage= {0, "", 0}; + thd->ENTER_COND(start_cond, cond_lock, + & stage_waiting_for_slave_thread_to_start, + & saved_stage); /* It is not sufficient to test this at loop bottom. We must test it after registering the mutex in enter_cond(). If the kill @@ -750,7 +764,7 @@ int start_slave_thread( */ if (!thd->killed) mysql_cond_wait(start_cond, cond_lock); - thd->exit_cond(old_msg); + thd->EXIT_COND(& saved_stage); mysql_mutex_lock(cond_lock); // re-acquire it as exit_cond() released if (thd->killed) { @@ -1811,15 +1825,15 @@ static bool wait_for_relay_log_space(Relay_log_info* rli) { bool slave_killed=0; Master_info* mi = rli->mi; - const char *save_proc_info; + PSI_stage_info old_stage; THD* thd = mi->io_thd; DBUG_ENTER("wait_for_relay_log_space"); mysql_mutex_lock(&rli->log_space_lock); - save_proc_info= thd->enter_cond(&rli->log_space_cond, - &rli->log_space_lock, - "\ -Waiting for the slave SQL thread to free enough relay log space"); + thd->ENTER_COND(&rli->log_space_cond, + &rli->log_space_lock, + &stage_waiting_for_relay_log_space, + &old_stage); while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi)) && !rli->ignore_log_space_limit) @@ -1874,7 +1888,7 @@ Waiting for the slave SQL thread to free enough relay log space"); rli->ignore_log_space_limit= false; } - thd->exit_cond(save_proc_info); + thd->EXIT_COND(&old_stage); DBUG_RETURN(slave_killed); } @@ -2113,6 +2127,10 @@ static bool send_show_master_info_header(THD *thd, bool full) FN_REFLEN)); field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong), MYSQL_TYPE_LONG)); + field_list.push_back(new Item_empty_string("Master_SSL_Crl", + sizeof(mi->ssl_crl))); + field_list.push_back(new Item_empty_string("Master_SSL_Crlpath", + sizeof(mi->ssl_crlpath))); if (full) { field_list.push_back(new Item_return_int("Retried_transactions", @@ -2126,6 +2144,7 @@ static bool send_show_master_info_header(THD *thd, bool full) field_list.push_back(new Item_float("Slave_heartbeat_period", 0.0, 3, 10)); } + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -2156,9 +2175,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full) &my_charset_bin); mysql_mutex_lock(&mi->run_lock); if (full) - protocol->store(mi->rli.sql_thd ? mi->rli.sql_thd->proc_info : "", + protocol->store(mi->rli.sql_thd ? mi->rli.sql_thd->get_proc_info() : "", &my_charset_bin); - protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); + protocol->store(mi->io_thd ? mi->io_thd->get_proc_info() : "", &my_charset_bin); mysql_mutex_unlock(&mi->run_lock); mysql_mutex_lock(&mi->data_lock); @@ -2288,6 +2307,10 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full) } // Master_Server_id protocol->store((uint32) mi->master_id); + // Master_Ssl_Crl + protocol->store(mi->ssl_ca, &my_charset_bin); + // Master_Ssl_Crlpath + protocol->store(mi->ssl_capath, &my_charset_bin); if (full) { protocol->store((uint32) mi->rli.retried_trans); @@ -2459,9 +2482,9 @@ static int init_slave_thread(THD* thd, Master_info *mi, mysql_mutex_unlock(&LOCK_thread_count); if (thd_type == SLAVE_THD_SQL) - thd_proc_info(thd, "Waiting for the next event in relay log"); + THD_STAGE_INFO(thd, stage_waiting_for_the_next_event_in_relay_log); else - thd_proc_info(thd, "Waiting for master update"); + THD_STAGE_INFO(thd, stage_waiting_for_master_update); thd->set_time(); /* Do not use user-supplied timeout value for system threads. */ thd->variables.lock_wait_timeout= LONG_TIMEOUT; @@ -2485,7 +2508,6 @@ static inline bool slave_sleep(THD *thd, time_t seconds, bool ret; struct timespec abstime; - const char *old_proc_info; mysql_mutex_t *lock= &info->sleep_lock; mysql_cond_t *cond= &info->sleep_cond; @@ -2493,7 +2515,7 @@ static inline bool slave_sleep(THD *thd, time_t seconds, /* Absolute system time at which the sleep time expires. */ set_timespec(abstime, seconds); mysql_mutex_lock(lock); - old_proc_info= thd->enter_cond(cond, lock, thd->proc_info); + thd->ENTER_COND(cond, lock, NULL, NULL); while (! (ret= func(thd, info))) { @@ -2502,7 +2524,7 @@ static inline bool slave_sleep(THD *thd, time_t seconds, break; } /* Implicitly unlocks the mutex. */ - thd->exit_cond(old_proc_info); + thd->EXIT_COND(NULL); return ret; } @@ -3216,7 +3238,7 @@ pthread_handler_t handle_slave_io(void *arg) goto err; } - thd_proc_info(thd, "Connecting to master"); + THD_STAGE_INFO(thd, stage_connecting_to_master); // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) { @@ -3254,7 +3276,7 @@ connected: // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; - thd_proc_info(thd, "Checking master version"); + THD_STAGE_INFO(thd, stage_checking_master_version); ret= get_master_version_and_clock(mysql, mi); if (ret == 1) /* Fatal error */ @@ -3278,7 +3300,7 @@ connected: /* Register ourselves with the master. */ - thd_proc_info(thd, "Registering slave on master"); + THD_STAGE_INFO(thd, stage_registering_slave_on_master); if (register_slave_on_master(mysql, mi, &suppress_warnings)) { if (!check_io_slave_killed(thd, mi, "Slave I/O thread killed " @@ -3308,7 +3330,7 @@ connected: DBUG_PRINT("info",("Starting reading binary log from master")); while (!io_slave_killed(thd,mi)) { - thd_proc_info(thd, "Requesting binlog dump"); + THD_STAGE_INFO(thd, stage_requesting_binlog_dump); if (request_dump(thd, mysql, mi, &suppress_warnings)) { sql_print_error("Failed on request_dump()"); @@ -3341,7 +3363,7 @@ requesting master dump") || important thing is to not confuse users by saying "reading" whereas we're in fact receiving nothing. */ - thd_proc_info(thd, "Waiting for master to send event"); + THD_STAGE_INFO(thd, stage_waiting_for_master_to_send_event); event_len= read_event(mysql, mi, &suppress_warnings); if (check_io_slave_killed(thd, mi, "Slave I/O thread killed while \ reading event")) @@ -3389,7 +3411,7 @@ Stopping slave I/O thread due to out-of-memory error from master"); } // if (event_len == packet_error) retry_count=0; // ok event, reset retry counter - thd_proc_info(thd, "Queueing master event to the relay log"); + THD_STAGE_INFO(thd, stage_queueing_master_event_to_the_relay_log); event_buf= (const char*)mysql->net.read_pos + 1; if (RUN_HOOK(binlog_relay_io, after_read_event, (thd, mi,(const char*)mysql->net.read_pos + 1, @@ -3486,7 +3508,7 @@ err: mi->mysql=0; } write_ignored_events_info_to_relay_log(thd, mi); - thd_proc_info(thd, "Waiting for slave mutex on exit"); + THD_STAGE_INFO(thd, stage_waiting_for_slave_mutex_on_exit); mysql_mutex_lock(&mi->run_lock); err_during_init: @@ -3762,7 +3784,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, while (!sql_slave_killed(thd,rli)) { - thd_proc_info(thd, "Reading event from the relay log"); + THD_STAGE_INFO(thd, stage_reading_event_from_the_relay_log); DBUG_ASSERT(rli->sql_thd == thd); THD_CHECK_SENTRY(thd); @@ -3875,7 +3897,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ thd->catalog= 0; thd->reset_query(); thd->reset_db(NULL, 0); - thd_proc_info(thd, "Waiting for slave mutex on exit"); + THD_STAGE_INFO(thd, stage_waiting_for_slave_mutex_on_exit); mysql_mutex_lock(&rli->run_lock); err_during_init: /* We need data_lock, at least to wake up any waiting master_pos_wait() */ @@ -4815,6 +4837,10 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, mi->ssl_cipher[0]?mi->ssl_cipher:0); mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &mi->ssl_verify_server_cert); + mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, + mi->ssl_crlpath[0] ? mi->ssl_crlpath : 0); + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &mi->ssl_verify_server_cert); } #endif diff --git a/sql/sp.cc b/sql/sp.cc index b80fa968483..9cc68339d6f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -377,7 +377,7 @@ void Proc_table_intact::report_error(uint code, const char *fmt, ...) if (code) my_message(code, buf, MYF(0)); else - my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "proc"); + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "proc"); if (m_print_once) { @@ -1396,9 +1396,9 @@ public: { if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE || - sql_errno == ER_CANNOT_LOAD_FROM_TABLE || + sql_errno == ER_CANNOT_LOAD_FROM_TABLE_V2 || sql_errno == ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE || - sql_errno == ER_COL_COUNT_DOESNT_MATCH_CORRUPTED) + sql_errno == ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2) return true; return false; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index cb9c0325845..7cd2e789351 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -385,9 +385,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) */ thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; - thd->abort_on_warning= - thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES); + thd->abort_on_warning= thd->is_strict_mode(); thd->transaction.stmt.modified_non_trans_table= FALSE; /* Save the value in the field. Convert the value if needed. */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2f854251ce5..cb7e35fae09 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* @@ -763,67 +763,68 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) acl_cache->clear(1); // Clear locked hostname cache init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); - if (init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, - FALSE)) - goto end; - - table->use_all_columns(); (void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST), 20, 50, MYF(0)); - while (!(read_record_info.read_record(&read_record_info))) + if (tables[0].table) // "host" table may not exist (e.g. in MySQL 5.6.7+) { - ACL_HOST host; - update_hostname(&host.host,get_field(&mem, table->field[0])); - host.db= get_field(&mem, table->field[1]); - if (lower_case_table_names && host.db) + if (init_read_record(&read_record_info, thd, table= tables[0].table, + NULL, 1, 1, FALSE)) + goto end; + table->use_all_columns(); + while (!(read_record_info.read_record(&read_record_info))) { - /* - convert db to lower case and give a warning if the db wasn't - already in lower case - */ - char *end = strnmov(tmp_name, host.db, sizeof(tmp_name)); - if (end >= tmp_name + sizeof(tmp_name)) + ACL_HOST host; + update_hostname(&host.host,get_field(&mem, table->field[0])); + host.db= get_field(&mem, table->field[1]); + if (lower_case_table_names && host.db) { - sql_print_warning(ER(ER_WRONG_DB_NAME), host.db); - continue; + /* + convert db to lower case and give a warning if the db wasn't + already in lower case + */ + char *end = strnmov(tmp_name, host.db, sizeof(tmp_name)); + if (end >= tmp_name + sizeof(tmp_name)) + { + sql_print_warning(ER(ER_WRONG_DB_NAME), host.db); + continue; + } + my_casedn_str(files_charset_info, host.db); + if (strcmp(host.db, tmp_name) != 0) + sql_print_warning("'host' entry '%s|%s' had database in mixed " + "case that has been forced to lowercase because " + "lower_case_table_names is set. It will not be " + "possible to remove this privilege using REVOKE.", + host.host.hostname ? host.host.hostname : "", + host.db ? host.db : ""); } - my_casedn_str(files_charset_info, host.db); - if (strcmp(host.db, tmp_name) != 0) - sql_print_warning("'host' entry '%s|%s' had database in mixed " - "case that has been forced to lowercase because " - "lower_case_table_names is set. It will not be " - "possible to remove this privilege using REVOKE.", + host.access= get_access(table,2); + host.access= fix_rights_for_db(host.access); + host.sort= get_sort(2,host.host.hostname,host.db); + if (check_no_resolve && hostname_requires_resolving(host.host.hostname)) + { + sql_print_warning("'host' entry '%s|%s' " + "ignored in --skip-name-resolve mode.", host.host.hostname ? host.host.hostname : "", host.db ? host.db : ""); - } - host.access= get_access(table,2); - host.access= fix_rights_for_db(host.access); - host.sort= get_sort(2,host.host.hostname,host.db); - if (check_no_resolve && hostname_requires_resolving(host.host.hostname)) - { - sql_print_warning("'host' entry '%s|%s' " - "ignored in --skip-name-resolve mode.", - host.host.hostname ? host.host.hostname : "", - host.db ? host.db : ""); - continue; - } + continue; + } #ifndef TO_BE_REMOVED - if (table->s->fields == 8) - { // Without grant - if (host.access & CREATE_ACL) - host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL; - } + if (table->s->fields == 8) + { // Without grant + if (host.access & CREATE_ACL) + host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL; + } #endif - (void) push_dynamic(&acl_hosts,(uchar*) &host); + (void) push_dynamic(&acl_hosts,(uchar*) &host); + } + my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, + sizeof(ACL_HOST),(qsort_cmp) acl_compare); + end_read_record(&read_record_info); } - my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, - sizeof(ACL_HOST),(qsort_cmp) acl_compare); - end_read_record(&read_record_info); freeze_size(&acl_hosts); - if (init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0, - FALSE)) + if (init_read_record(&read_record_info, thd, table=tables[1].table, + NULL, 1, 1, FALSE)) goto end; - table->use_all_columns(); (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0)); password_length= table->field[2]->field_length / @@ -1022,10 +1023,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_users); - if (init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0, - FALSE)) + if (init_read_record(&read_record_info, thd, table=tables[2].table, + NULL, 1, 1, FALSE)) goto end; - table->use_all_columns(); (void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB), 50, 100, MYF(0)); while (!(read_record_info.read_record(&read_record_info))) @@ -1093,8 +1093,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) 50, 100, MYF(0)); if (tables[3].table) { - init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1, - 0, FALSE); + if (init_read_record(&read_record_info, thd, table= tables[3].table, + NULL, 1, 1, FALSE)) + goto end; table->use_all_columns(); while (!(read_record_info.read_record(&read_record_info))) { @@ -1198,7 +1199,7 @@ my_bool acl_reload(THD *thd) tables[2].next_local= tables[2].next_global= tables + 3; tables[0].open_type= tables[1].open_type= tables[2].open_type= tables[3].open_type= OT_BASE_ONLY; - tables[3].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; + tables[0].open_strategy= tables[3].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { @@ -1327,7 +1328,7 @@ static ulong get_sort(uint count,...) chars= 128; // Marker that chars existed } } - sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars); + sort= (sort << 8) + (wild_pos ? min(wild_pos, 127U) : chars); } va_end(args); return sort; @@ -3951,7 +3952,6 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, db_name= table_list->db; table_name= table_list->table_name; - grant_name= routine_hash_search(Str->host.str, NullS, db_name, Str->user.str, table_name, is_proc, 1); if (!grant_name) @@ -4088,6 +4088,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, result= TRUE; continue; } + /* No User, but a password? They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... ! @@ -4095,6 +4096,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, */ if (!tmp_Str->user.str && tmp_Str->password.str) Str->password= tmp_Str->password; + if (replace_user_table(thd, tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users, test(thd->variables.sql_mode & @@ -5687,7 +5689,7 @@ void get_privilege_desc(char *to, uint max_length, ulong access) { uint pos; char *start=to; - DBUG_ASSERT(max_length >= 30); // For end ',' removal + DBUG_ASSERT(max_length >= 30); // For end ', ' removal if (access) { @@ -5698,9 +5700,11 @@ void get_privilege_desc(char *to, uint max_length, ulong access) command_lengths[pos] + (uint) (to-start) < max_length) { to= strmov(to, command_array[pos]); - *to++=','; + *to++= ','; + *to++= ' '; } } + to--; // Remove end ' ' to--; // Remove end ',' } *to=0; @@ -9156,6 +9160,13 @@ bool acl_authenticate(THD *thd, uint connect_errors, else my_ok(thd); +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_user_host)(thd->main_security_ctx.user, + strlen(thd->main_security_ctx.user), + thd->main_security_ctx.host_or_ip, + strlen(thd->main_security_ctx.host_or_ip)); +#endif + /* Ready to handle queries */ DBUG_RETURN(0); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b3321bd2771..969e2f2c7e4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -534,6 +534,7 @@ static void table_def_unuse_table(TABLE *table) DBUG_ASSERT(! table->s->has_old_version()); table->in_use= 0; + /* Remove table from the list of tables used in this share. */ table->s->used_tables.remove(table); /* Add table to the list of unused TABLE objects for this share. */ @@ -632,6 +633,13 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, DBUG_RETURN(0); } share->ref_count++; // Mark in use + +#ifdef HAVE_PSI_TABLE_INTERFACE + share->m_psi= PSI_CALL(get_table_share)(false, share); +#else + share->m_psi= NULL; +#endif + DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u", (ulong) share, share->ref_count)); DBUG_RETURN(share); @@ -1640,6 +1648,10 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) table->file->ha_reset(); } + /* Do this *before* entering the LOCK_open critical section. */ + if (table->file != NULL) + table->file->unbind_psi(); + mysql_mutex_lock(&LOCK_open); if (table->s->has_old_version() || table->needs_reopen() || @@ -2743,6 +2755,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, int error; TABLE_SHARE *share; my_hash_value_type hash_value; + bool recycled_free_table; + DBUG_ENTER("open_table"); /* an open table operation needs a lot of the stack space */ @@ -2927,6 +2941,19 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK)) { /* + Check if we're trying to take a write lock in a read only transaction. + */ + if (table_list->mdl_request.type >= MDL_SHARED_WRITE && + thd->tx_read_only && + !(flags & (MYSQL_OPEN_HAS_MDL_LOCK | + MYSQL_LOCK_LOG_TABLE | + MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY))) + { + my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0)); + DBUG_RETURN(true); + } + + /* We are not under LOCK TABLES and going to acquire write-lock/ modify the base table. We need to acquire protection against global read lock until end of this statement in order to have @@ -3039,6 +3066,11 @@ retry_share: DBUG_RETURN(TRUE); } + /* + Check if this TABLE_SHARE-object corresponds to a view. Note, that there is + no need to call TABLE_SHARE::has_old_version() as we do for regular tables, + because view shares are always up to date. + */ if (share->is_view) { /* @@ -3148,6 +3180,7 @@ retry_share: { table= share->free_tables.front(); table_def_use_table(thd, table); + recycled_free_table= true; /* We need to release share as we have EXTRA reference to it in our hands. */ release_table_share(share); } @@ -3159,6 +3192,7 @@ retry_share: mysql_mutex_unlock(&LOCK_open); + recycled_free_table= false; /* make a new table */ if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME)))) goto err_lock; @@ -3200,6 +3234,13 @@ retry_share: mysql_mutex_unlock(&LOCK_open); + /* Call rebind_psi outside of the LOCK_open critical section. */ + if (recycled_free_table) + { + DBUG_ASSERT(table->file != NULL); + table->file->rebind_psi(); + } + table->mdl_ticket= mdl_ticket; table->next= thd->open_tables; /* Link into simple list */ @@ -4754,6 +4795,15 @@ lock_table_names(THD *thd, ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) && find_temporary_table(thd, table)))) { + /* + Write lock on normal tables is not allowed in a read only transaction. + */ + if (thd->tx_read_only) + { + my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0)); + DBUG_RETURN(true); + } + if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && schema_set.insert(table)) DBUG_RETURN(TRUE); @@ -4992,7 +5042,7 @@ restart: table_to_open= start; sroutine_to_open= (Sroutine_hash_entry**) &thd->lex->sroutines_list.first; *counter= 0; - thd_proc_info(thd, "Opening tables"); + THD_STAGE_INFO(thd, stage_opening_tables); /* If we are executing LOCK TABLES statement or a DDL statement @@ -5184,7 +5234,6 @@ restart: } err: - thd_proc_info(thd, 0); free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (error && *table_to_open) @@ -5564,7 +5613,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, /* should not be used in a prelocked_mode context, see NOTE above */ DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED); - thd_proc_info(thd, "Opening table"); + THD_STAGE_INFO(thd, stage_opening_tables); thd->current_tablenr= 0; /* open_ltable can be used only for BASIC TABLEs */ table_list->required_type= FRMTYPE_TABLE; @@ -5633,7 +5682,6 @@ end: trans_rollback_stmt(thd); close_thread_tables(thd); } - thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -5883,7 +5931,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, query_table->lock_type >= TL_WRITE_ALLOW_WRITE && unique_keys > 1 && thd->lex->sql_command == SQLCOM_INSERT && /* Duplicate key update is not supported by INSERT DELAYED */ - thd->command != COM_DELAYED_INSERT && + thd->get_command() != COM_DELAYED_INSERT && thd->lex->duplicates == DUP_UPDATE) thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS); } @@ -6120,8 +6168,21 @@ TABLE *open_table_uncached(THD *thd, const char *path, const char *db, init_tmp_table_share(thd, share, saved_cache_key, key_length, strend(saved_cache_key)+1, tmp_path); - if (open_table_def(thd, share, 0) || - open_table_from_share(thd, share, table_name, + if (open_table_def(thd, share, 0)) + { + /* No need to lock share->mutex as this is not needed for tmp tables */ + free_table_share(share); + my_free(tmp_table); + DBUG_RETURN(0); + } + +#ifdef HAVE_PSI_TABLE_INTERFACE + share->m_psi= PSI_CALL(get_table_share)(true, share); +#else + share->m_psi= NULL; +#endif + + if (open_table_from_share(thd, share, table_name, (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX), READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, @@ -9491,7 +9552,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - thd_proc_info(thd, "FULLTEXT initialization"); + THD_STAGE_INFO(thd, stage_fulltext_initialization); while ((ifm=li++)) ifm->init_search(no_order); diff --git a/sql/sql_bootstrap.cc b/sql/sql_bootstrap.cc new file mode 100644 index 00000000000..8e632a02ace --- /dev/null +++ b/sql/sql_bootstrap.cc @@ -0,0 +1,120 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + + +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> +#include "sql_bootstrap.h" + +int read_bootstrap_query(char *query, int *query_length, + fgets_input_t input, fgets_fn_t fgets_fn, int *error) +{ + char line_buffer[MAX_BOOTSTRAP_LINE_SIZE]; + const char *line; + int len; + int query_len= 0; + int fgets_error= 0; + *error= 0; + + for ( ; ; ) + { + line= (*fgets_fn)(line_buffer, sizeof(line_buffer), input, &fgets_error); + + if (error) + *error= fgets_error; + + if (fgets_error != 0) + return READ_BOOTSTRAP_ERROR; + + if (line == NULL) + return (query_len == 0) ? READ_BOOTSTRAP_EOF : READ_BOOTSTRAP_ERROR; + + len= strlen(line); + + /* + Remove trailing whitespace characters. + This assumes: + - no multibyte encoded character can be found at the very end of a line, + - whitespace characters from the "C" locale only. + which is sufficient for the kind of queries found + in the bootstrap scripts. + */ + while (len && (isspace(line[len - 1]))) + len--; + /* + Cleanly end the string, so we don't have to test len > x + all the time before reading line[x], in the code below. + */ + line_buffer[len]= '\0'; + + /* Skip blank lines */ + if (len == 0) + continue; + + /* Skip # comments */ + if (line[0] == '#') + continue; + + /* Skip -- comments */ + if ((line[0] == '-') && (line[1] == '-')) + continue; + + /* Skip delimiter, ignored. */ + if (strncmp(line, "delimiter", 9) == 0) + continue; + + /* Append the current line to a multi line query. If the new line will make + the query too long, preserve the partial line to provide context for the + error message. + */ + if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE) + { + int new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1; + if ((new_len > 0) && (query_len < MAX_BOOTSTRAP_QUERY_SIZE)) + { + memcpy(query + query_len, line, new_len); + query_len+= new_len; + } + query[query_len]= '\0'; + *query_length= query_len; + return READ_BOOTSTRAP_QUERY_SIZE; + } + + if (query_len != 0) + { + /* + Append a \n to the current line, if any, + to preserve the intended presentation. + */ + query[query_len++]= '\n'; + } + memcpy(query + query_len, line, len); + query_len+= len; + + if (line[len - 1] == ';') + { + /* + The last line is terminated by ';'. + Return the query found. + */ + query[query_len]= '\0'; + *query_length= query_len; + return READ_BOOTSTRAP_SUCCESS; + } + } +} + diff --git a/sql/sql_bootstrap.h b/sql/sql_bootstrap.h new file mode 100644 index 00000000000..b8a302a8646 --- /dev/null +++ b/sql/sql_bootstrap.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + + +#ifndef SQL_BOOTSTRAP_H +#define SQL_BOOTSTRAP_H + +/** + The maximum size of a bootstrap query. + Increase this size if parsing a longer query during bootstrap is necessary. + The longest query in use depends on the documentation content, + see the file fill_help_tables.sql +*/ +#define MAX_BOOTSTRAP_QUERY_SIZE 20000 +/** + The maximum size of a bootstrap query, expressed in a single line. + Do not increase this size, use the multiline syntax instead. +*/ +#define MAX_BOOTSTRAP_LINE_SIZE 20000 +#define MAX_BOOTSTRAP_ERROR_LEN 256 + +#define READ_BOOTSTRAP_SUCCESS 0 +#define READ_BOOTSTRAP_EOF 1 +#define READ_BOOTSTRAP_ERROR 2 +#define READ_BOOTSTRAP_QUERY_SIZE 3 + +typedef void *fgets_input_t; +typedef char * (*fgets_fn_t)(char *, size_t, fgets_input_t, int *error); + +int read_bootstrap_query(char *query, int *query_length, + fgets_input_t input, fgets_fn_t fgets_fn, int *error); + +#endif + + diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index ddc75254c9e..f5e1deab546 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -10,8 +11,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /* Description of the query cache: @@ -411,23 +412,28 @@ const uchar *query_state_map; struct Query_cache_wait_state { THD *m_thd; - const char *m_proc_info; + PSI_stage_info m_old_stage; + const char *m_func; + const char *m_file; + int m_line; Query_cache_wait_state(THD *thd, const char *func, const char *file, unsigned int line) : m_thd(thd), - m_proc_info(NULL) + m_old_stage(), + m_func(func), m_file(file), m_line(line) { if (m_thd) - m_proc_info= set_thd_proc_info(m_thd, - "Waiting for query cache lock", - func, file, line); + set_thd_stage_info(m_thd, + &stage_waiting_for_query_cache_lock, + &m_old_stage, + m_func, m_file, m_line); } ~Query_cache_wait_state() { if (m_thd) - set_thd_proc_info(m_thd, m_proc_info, NULL, NULL, 0); + set_thd_stage_info(m_thd, &m_old_stage, NULL, m_func, m_file, m_line); } }; @@ -1140,7 +1146,7 @@ Query_cache::abort(Query_cache_tls *query_cache_tls) if (query_block) { thd= current_thd; - thd_proc_info(thd, "storing result in query cache"); + THD_STAGE_INFO(thd, stage_storing_result_in_query_cache); DUMP(this); BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block @@ -1191,7 +1197,7 @@ void Query_cache::end_of_result(THD *thd) suitable size if needed and setting block type. Since this is the last block, the writer should be dropped. */ - thd_proc_info(thd, "storing result in query cache"); + THD_STAGE_INFO(thd, stage_storing_result_in_query_cache); DUMP(this); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); @@ -1850,7 +1856,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) DBUG_PRINT("qcache", ("No active database")); } - thd_proc_info(thd, "checking query cache for query"); + THD_STAGE_INFO(thd, stage_checking_query_cache_for_query); // fill all gaps between fields with 0 to get repeatable key bzero(&flags, QUERY_CACHE_FLAGS_SIZE); @@ -1941,7 +1947,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", } // Check access; - thd_proc_info(thd, "checking privileges on cached query"); + THD_STAGE_INFO(thd, stage_checking_privileges_on_cached_query); block_table= query_block->table(0); block_table_end= block_table+query_block->n_tables; for (; block_table != block_table_end; block_table++) @@ -2047,7 +2053,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", Send cached result to client */ #ifndef EMBEDDED_LIBRARY - thd_proc_info(thd, "sending cached result to client"); + THD_STAGE_INFO(thd, stage_sending_cached_result_to_client); do { DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)", @@ -2148,7 +2154,7 @@ void Query_cache::invalidate(THD *thd, CHANGED_TABLE_LIST *tables_used) for (; tables_used; tables_used= tables_used->next) { - thd_proc_info(thd, "invalidating query cache entries (table list)"); + THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table_list); invalidate_table(thd, (uchar*) tables_used->key, tables_used->key_length); DBUG_PRINT("qcache", ("db: %s table: %s", tables_used->key, tables_used->key+ @@ -2177,7 +2183,7 @@ void Query_cache::invalidate_locked_for_write(THD *thd, for (; tables_used; tables_used= tables_used->next_local) { - thd_proc_info(thd, "invalidating query cache entries (table)"); + THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table); if (tables_used->lock_type >= TL_WRITE_ALLOW_WRITE && tables_used->table) { @@ -2305,6 +2311,9 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename) { DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename"); + if (is_disabled()) + DBUG_VOID_RETURN; + /* Calculate the key outside the lock to make the lock shorter */ char key[MAX_DBKEY_LENGTH]; uint32 db_length; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7577056c3c5..a068cdc8f88 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -478,7 +478,7 @@ void thd_set_mysys_var(THD *thd, st_my_thread_var *mysys_var) */ my_socket thd_get_fd(THD *thd) { - return thd->net.vio->sd; + return mysql_socket_getfd(thd->net.vio->mysql_socket); } #endif @@ -544,44 +544,93 @@ int thd_tablespace_op(const THD *thd) return test(thd->tablespace_op); } - extern "C" -const char *set_thd_proc_info(THD *thd, const char *info, +const char *set_thd_proc_info(THD *thd_arg, const char *info, const char *calling_function, const char *calling_file, const unsigned int calling_line) { - if (!thd) + PSI_stage_info old_stage; + PSI_stage_info new_stage; + + old_stage.m_key= 0; + old_stage.m_name= info; + + set_thd_stage_info(thd_arg, & old_stage, & new_stage, + calling_function, calling_file, calling_line); + + return new_stage.m_name; +} + +extern "C" +void set_thd_stage_info(void *thd_arg, + const PSI_stage_info *new_stage, + PSI_stage_info *old_stage, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line) +{ + THD *thd= (THD*) thd_arg; + if (thd == NULL) thd= current_thd; - const char *old_info= thd->proc_info; - DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line, info)); + thd->enter_stage(new_stage, old_stage, calling_func, calling_file, + calling_line); +} + +void THD::enter_stage(const PSI_stage_info *new_stage, + PSI_stage_info *old_stage, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line) +{ + DBUG_PRINT("THD::enter_stage", ("%s:%d", calling_file, calling_line)); + + if (old_stage != NULL) + { + old_stage->m_key= m_current_stage_key; + old_stage->m_name= proc_info; + } + + if (new_stage != NULL) + { + const char *msg= new_stage->m_name; #if defined(ENABLED_PROFILING) - thd->profiling.status_change(info, - calling_function, calling_file, calling_line); + profiling.status_change(msg, calling_func, calling_file, calling_line); +#endif + + m_current_stage_key= new_stage->m_key; + proc_info= msg; + +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_state)(msg); + MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line); #endif - thd->proc_info= info; - return old_info; + } + return; } -extern "C" -const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, - mysql_mutex_t *mutex, const char *msg) +void thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, mysql_mutex_t *mutex, + const PSI_stage_info *stage, PSI_stage_info *old_stage, + const char *src_function, const char *src_file, + int src_line) { if (!thd) thd= current_thd; - return thd->enter_cond(cond, mutex, msg); + return thd->enter_cond(cond, mutex, stage, old_stage, src_function, src_file, + src_line); } -extern "C" -void thd_exit_cond(MYSQL_THD thd, const char *old_msg) +void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage, + const char *src_function, const char *src_file, + int src_line) { if (!thd) thd= current_thd; - thd->exit_cond(old_msg); + thd->exit_cond(stage, src_function, src_file, src_line); return; } @@ -646,6 +695,12 @@ int thd_tx_isolation(const THD *thd) } extern "C" +int thd_tx_is_read_only(const THD *thd) +{ + return (int) thd->tx_read_only; +} + +extern "C" void thd_inc_row_count(THD *thd) { thd->warning_info->inc_current_row_for_warning(); @@ -790,10 +845,13 @@ THD::THD() first_successful_insert_id_in_prev_stmt_for_binlog(0), first_successful_insert_id_in_cur_stmt(0), stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), - examined_row_count(0), + m_examined_row_count(0), accessed_rows_and_keys(0), warning_info(&main_warning_info), stmt_da(&main_da), + m_statement_psi(NULL), + m_idle_psi(NULL), + m_server_idle(false), thread_id(0), global_disable_checkpoint(0), failed_com_change_user(0), @@ -852,7 +910,7 @@ THD::THD() my_hash_clear(&handler_tables_hash); tmp_table=0; cuted_fields= 0L; - sent_row_count= 0L; + m_sent_row_count= 0L; limit_found_rows= 0; m_row_count_func= -1; statement_id_counter= 0UL; @@ -916,7 +974,7 @@ THD::THD() where= THD::DEFAULT_WHERE; server_id = ::server_id; slave_net = 0; - command=COM_CONNECT; + m_command=COM_CONNECT; *scramble= '\0'; /* Call to init() below requires fully initialized Open_tables_state. */ @@ -1258,6 +1316,7 @@ void THD::init(void) TL_WRITE_LOW_PRIORITY : TL_WRITE); tx_isolation= (enum_tx_isolation) variables.tx_isolation; + tx_read_only= variables.tx_read_only; update_charset(); reset_current_stmt_binlog_format_row(); set_status_var_init(); @@ -2392,7 +2451,7 @@ int select_send::send_data(List<Item> &items) DBUG_RETURN(TRUE); } - thd->sent_row_count++; + thd->inc_sent_row_count(1); if (thd->vio_ok()) DBUG_RETURN(protocol->write()); @@ -2485,7 +2544,7 @@ select_to_file::~select_to_file() select_export::~select_export() { - thd->sent_row_count=row_count; + thd->set_sent_row_count(row_count); } @@ -3925,6 +3984,7 @@ extern "C" enum thd_kill_levels thd_kill_level(const MYSQL_THD thd) return thd->killed & KILL_HARD_BIT ? THD_ABORT_ASAP : THD_ABORT_SOFTLY; } + /** Send an out-of-band progress report to the client @@ -4221,8 +4281,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, backup->enable_slow_log= enable_slow_log; backup->query_plan_flags= query_plan_flags; backup->limit_found_rows= limit_found_rows; - backup->examined_row_count= examined_row_count; - backup->sent_row_count= sent_row_count; + backup->examined_row_count= m_examined_row_count; + backup->sent_row_count= m_sent_row_count; backup->cuted_fields= cuted_fields; backup->client_capabilities= client_capabilities; backup->savepoints= transaction.savepoints; @@ -4245,8 +4305,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, /* Disable result sets */ client_capabilities &= ~CLIENT_MULTI_RESULTS; in_sub_stmt|= new_state; - examined_row_count= 0; - sent_row_count= 0; + m_examined_row_count= 0; + m_sent_row_count= 0; cuted_fields= 0; transaction.savepoints= 0; first_successful_insert_id_in_cur_stmt= 0; @@ -4293,7 +4353,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) first_successful_insert_id_in_cur_stmt= backup->first_successful_insert_id_in_cur_stmt; limit_found_rows= backup->limit_found_rows; - sent_row_count= backup->sent_row_count; + set_sent_row_count(backup->sent_row_count); client_capabilities= backup->client_capabilities; /* If we've left sub-statement mode, reset the fatal error flag. @@ -4311,7 +4371,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) The following is added to the old values as we are interested in the total complexity of the query */ - examined_row_count+= backup->examined_row_count; + inc_examined_row_count(backup->examined_row_count); cuted_fields+= backup->cuted_fields; DBUG_VOID_RETURN; } @@ -4324,6 +4384,141 @@ void THD::set_statement(Statement *stmt) mysql_mutex_unlock(&LOCK_thd_data); } +void THD::set_sent_row_count(ha_rows count) +{ + m_sent_row_count= count; + MYSQL_SET_STATEMENT_ROWS_SENT(m_statement_psi, m_sent_row_count); +} + +void THD::set_examined_row_count(ha_rows count) +{ + m_examined_row_count= count; + MYSQL_SET_STATEMENT_ROWS_EXAMINED(m_statement_psi, m_examined_row_count); +} + +void THD::inc_sent_row_count(ha_rows count) +{ + m_sent_row_count+= count; + MYSQL_SET_STATEMENT_ROWS_SENT(m_statement_psi, m_sent_row_count); +} + +void THD::inc_examined_row_count(ha_rows count) +{ + m_examined_row_count+= count; + MYSQL_SET_STATEMENT_ROWS_EXAMINED(m_statement_psi, m_examined_row_count); +} + +void THD::inc_status_created_tmp_disk_tables() +{ + status_var_increment(status_var.created_tmp_disk_tables_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_created_tmp_tables() +{ + status_var_increment(status_var.created_tmp_tables_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_select_full_join() +{ + status_var_increment(status_var.select_full_join_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_select_full_join)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_select_full_range_join() +{ + status_var_increment(status_var.select_full_range_join_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_select_full_range_join)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_select_range() +{ + status_var_increment(status_var.select_range_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_select_range)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_select_range_check() +{ + status_var_increment(status_var.select_range_check_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_select_range_check)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_select_scan() +{ + status_var_increment(status_var.select_scan_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_select_scan)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_sort_merge_passes() +{ + status_var_increment(status_var.filesort_merge_passes_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_sort_merge_passes)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_sort_range() +{ + status_var_increment(status_var.filesort_range_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_sort_range)(m_statement_psi, 1); +#endif +} + +void THD::inc_status_sort_rows(ha_rows count) +{ + statistic_add(status_var.filesort_rows_, count, &LOCK_status); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_sort_rows)(m_statement_psi, count); +#endif +} + +void THD::inc_status_sort_scan() +{ + status_var_increment(status_var.filesort_scan_count_); +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(inc_statement_sort_scan)(m_statement_psi, 1); +#endif +} + +void THD::set_status_no_index_used() +{ + server_status|= SERVER_QUERY_NO_INDEX_USED; +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(set_statement_no_index_used)(m_statement_psi); +#endif +} + +void THD::set_status_no_good_index_used() +{ + server_status|= SERVER_QUERY_NO_GOOD_INDEX_USED; +#ifdef HAVE_PSI_STATEMENT_INTERFACE + PSI_CALL(set_statement_no_good_index_used)(m_statement_psi); +#endif +} + +void THD::set_command(enum enum_server_command command) +{ + m_command= command; +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_command)(m_command); +#endif +} /** Assign a new value to thd->query. */ @@ -4332,6 +4527,10 @@ void THD::set_query(const CSET_STRING &string_arg) mysql_mutex_lock(&LOCK_thd_data); set_query_inner(string_arg); mysql_mutex_unlock(&LOCK_thd_data); + +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_info)(query(), query_length()); +#endif } /** Assign a new value to thd->query and thd->query_id. */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 87b9783c1ed..fccca9e8cbf 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -13,18 +13,13 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_CLASS_INCLUDED #define SQL_CLASS_INCLUDED /* Classes in mysql */ -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #ifdef MYSQL_SERVER #include "unireg.h" // REQUIRED: for other includes @@ -43,6 +38,23 @@ #include "violite.h" /* vio_is_connected */ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */ +#include <mysql/psi/mysql_stage.h> +#include <mysql/psi/mysql_statement.h> +#include <mysql/psi/mysql_idle.h> +#include <mysql/psi/mysql_table.h> +#include <mysql_com_server.h> + +extern "C" +void set_thd_stage_info(void *thd, + const PSI_stage_info *new_stage, + PSI_stage_info *old_stage, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line); + +#define THD_STAGE_INFO(thd, stage) \ + (thd)->enter_stage(& stage, NULL, __func__, __FILE__, __LINE__) + #include "my_apc.h" class Reprepare_observer; @@ -67,7 +79,7 @@ enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, SLAVE_EXEC_MODE_IDEMPOTENT, - SLAVE_EXEC_MODE_LAST_BIT}; + SLAVE_EXEC_MODE_LAST_BIT }; enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY, SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY}; enum enum_mark_columns @@ -541,6 +553,10 @@ typedef struct system_variables ulong slave_skip_counter; ulong max_relay_log_size; + /** + Default transaction access mode. READ ONLY (true) or READ WRITE (false). + */ + my_bool tx_read_only; my_bool low_priority_updates; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; @@ -593,8 +609,8 @@ typedef struct system_status_var { ulong com_other; ulong com_stat[(uint) SQLCOM_END]; - ulong created_tmp_disk_tables; - ulong created_tmp_tables; + ulong created_tmp_disk_tables_; + ulong created_tmp_tables_; ulong ha_commit_count; ulong ha_delete_count; ulong ha_read_first_count; @@ -626,23 +642,24 @@ typedef struct system_status_var ulong ha_discover_count; ulong ha_savepoint_count; ulong ha_savepoint_rollback_count; + ulong ha_external_lock_count; ulong net_big_packet_count; ulong opened_tables; ulong opened_shares; ulong opened_views; /* +1 opening a view */ - ulong select_full_join_count; - ulong select_full_range_join_count; - ulong select_range_count; - ulong select_range_check_count; - ulong select_scan_count; + ulong select_full_join_count_; + ulong select_full_range_join_count_; + ulong select_range_count_; + ulong select_range_check_count_; + ulong select_scan_count_; ulong executed_triggers; ulong long_query_count; - ulong filesort_merge_passes; - ulong filesort_range_count; - ulong filesort_rows; - ulong filesort_scan_count; + ulong filesort_merge_passes_; + ulong filesort_range_count_; + ulong filesort_rows_; + ulong filesort_scan_count_; /* Prepared statements and binary protocol */ ulong com_stmt_prepare; ulong com_stmt_reprepare; @@ -1602,6 +1619,8 @@ public: Query_cache_tls query_cache_tls; #endif NET net; // client connection descriptor + /** Aditional network instrumentation for the server only. */ + NET_SERVER m_net_server_extension; scheduler_functions *scheduler; // Scheduler for this connection Protocol *protocol; // Current protocol Protocol_text protocol_text; // Normal protocol @@ -1667,6 +1686,19 @@ public: */ const char *proc_info; +private: + unsigned int m_current_stage_key; + +public: + void enter_stage(const PSI_stage_info *stage, + PSI_stage_info *old_stage, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line); + + const char *get_proc_info() const + { return proc_info; } + /* Used in error messages to tell user in what part of MySQL we found an error. E. g. when where= "having clause", if fix_fields() fails, user @@ -1688,11 +1720,14 @@ public: uint dbug_sentry; // watch out for memory corruption #endif struct st_my_thread_var *mysys_var; +private: /* Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from first byte of the packet in do_command() */ - enum enum_server_command command; + enum enum_server_command m_command; + +public: uint32 server_id; uint32 file_id; // for LOAD DATA INFILE /* remote (peer) port */ @@ -2110,11 +2145,12 @@ public: ha_rows cuted_fields; +private: /* number of rows we actually sent to the client, including "synthetic" rows in ROLLUP etc. */ - ha_rows sent_row_count; + ha_rows m_sent_row_count; /** Number of rows read and/or evaluated for a statement. Used for @@ -2126,12 +2162,42 @@ public: statement including ORDER BY could possibly evaluate the row in filesort() before reading it for e.g. update. */ - ha_rows examined_row_count; + ha_rows m_examined_row_count; + +public: + ha_rows get_sent_row_count() const + { return m_sent_row_count; } + + ha_rows get_examined_row_count() const + { return m_examined_row_count; } + + void set_sent_row_count(ha_rows count); + void set_examined_row_count(ha_rows count); + + void inc_sent_row_count(ha_rows count); + void inc_examined_row_count(ha_rows count); + + void inc_status_created_tmp_disk_tables(); + void inc_status_created_tmp_files(); + void inc_status_created_tmp_tables(); + void inc_status_select_full_join(); + void inc_status_select_full_range_join(); + void inc_status_select_range(); + void inc_status_select_range_check(); + void inc_status_select_scan(); + void inc_status_sort_merge_passes(); + void inc_status_sort_range(); + void inc_status_sort_rows(ha_rows count); + void inc_status_sort_scan(); + void set_status_no_index_used(); + void set_status_no_good_index_used(); + /** The number of rows and/or keys examined by the query, both read, changed or written. */ ulonglong accessed_rows_and_keys; + /** Check if the number of rows accessed by a statement exceeded LIMIT ROWS EXAMINED. If so, signal the query engine to stop execution. @@ -2150,6 +2216,21 @@ public: PROFILING profiling; #endif + /** Current statement instrumentation. */ + PSI_statement_locker *m_statement_psi; +#ifdef HAVE_PSI_STATEMENT_INTERFACE + /** Current statement instrumentation state. */ + PSI_statement_locker_state m_statement_state; +#endif /* HAVE_PSI_STATEMENT_INTERFACE */ + /** Idle instrumentation. */ + PSI_idle_locker *m_idle_psi; +#ifdef HAVE_PSI_IDLE_INTERFACE + /** Idle instrumentation state. */ + PSI_idle_locker_state m_idle_state; +#endif /* HAVE_PSI_IDLE_INTERFACE */ + /** True if the server code is IDLE for this connection. */ + bool m_server_idle; + /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. @@ -2197,6 +2278,11 @@ public: above. */ enum_tx_isolation tx_isolation; + /* + Current or next transaction access mode. + See comment above regarding tx_isolation. + */ + bool tx_read_only; enum_check_fields count_cuted_fields; DYNAMIC_ARRAY user_var_events; /* For user variables replication */ @@ -2457,22 +2543,20 @@ public: int errcode); #endif - /* - For enter_cond() / exit_cond() to work the mutex must be got before - enter_cond(); this mutex is then released by exit_cond(). - Usage must be: lock mutex; enter_cond(); your code; exit_cond(). - */ - inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex, - const char* msg) + inline void + enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex, + const PSI_stage_info *stage, PSI_stage_info *old_stage, + const char *src_function, const char *src_file, + int src_line) { - const char* old_msg = proc_info; mysql_mutex_assert_owner(mutex); mysys_var->current_mutex = mutex; mysys_var->current_cond = cond; - proc_info = msg; - return old_msg; + enter_stage(stage, old_stage, src_function, src_file, src_line); } - inline void exit_cond(const char* old_msg) + inline void exit_cond(const PSI_stage_info *stage, + const char *src_function, const char *src_file, + int src_line) { /* Putting the mutex unlock in thd->exit_cond() ensures that @@ -2484,10 +2568,15 @@ public: mysql_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex = 0; mysys_var->current_cond = 0; - proc_info = old_msg; + enter_stage(stage, NULL, src_function, src_file, src_line); mysql_mutex_unlock(&mysys_var->mutex); return; } + inline bool is_strict_mode() const + { + return variables.sql_mode & (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES); + } inline my_time_t query_start() { query_start_used=1; return start_time; } inline ulong query_start_sec_part() { query_start_sec_part_used=1; return start_time_sec_part; } @@ -2496,6 +2585,9 @@ public: my_hrtime_t hrtime= my_hrtime(); start_time= hrtime_to_my_time(hrtime); start_time_sec_part= hrtime_sec_part(hrtime); +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_start_time)(start_time); +#endif } inline void set_start_time() { @@ -2503,6 +2595,9 @@ public: { start_time= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_start_time)(start_time); +#endif } else set_current_time(); @@ -2522,7 +2617,12 @@ public: my_hrtime_t hrtime= { hrtime_from_time(t) + sec_part }; set_time(hrtime); } - void set_time_after_lock() { utime_after_lock= microsecond_interval_timer(); } + void set_time_after_lock() + { + utime_after_lock= microsecond_interval_timer(); + MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi, + (utime_after_lock - start_utime)); + } ulonglong current_utime() { return microsecond_interval_timer(); } /** @@ -2690,6 +2790,11 @@ public: To raise this flag, use my_error(). */ inline bool is_error() const { return stmt_da->is_error(); } + + /// Returns Diagnostics-area for the current statement. + Diagnostics_area *get_stmt_da() + { return stmt_da; } + inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); @@ -2911,6 +3016,7 @@ public: */ bool set_db(const char *new_db, size_t new_db_len) { + bool result; /* Do not reallocate memory if current chunk is big enough. */ if (db && new_db && db_length >= new_db_len) memcpy(db, new_db, new_db_len+1); @@ -2923,7 +3029,12 @@ public: db= NULL; } db_length= db ? new_db_len : 0; - return new_db && !db; + result= new_db && !db; +#ifdef HAVE_PSI_THREAD_INTERFACE + if (result) + PSI_CALL(set_thread_db)(new_db, new_db_len); +#endif + return result; } /** @@ -2941,6 +3052,9 @@ public: { db= new_db; db_length= new_db_len; +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_CALL(set_thread_db)(new_db, new_db_len); +#endif } /* Copy the current database to the argument. Use the current arena to @@ -3057,6 +3171,9 @@ private: public: /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); + void set_command(enum enum_server_command command); + inline enum enum_server_command get_command() const + { return m_command; } /** Assign a new value to thd->query and thd->query_id and mysys_var. @@ -3246,7 +3363,7 @@ my_eof(THD *thd) const my_bool strict_date_checking= 0; -inline ulong sql_mode_for_dates(THD *thd) +inline ulonglong sql_mode_for_dates(THD *thd) { if (strict_date_checking) return (thd->variables.sql_mode & @@ -3255,7 +3372,7 @@ inline ulong sql_mode_for_dates(THD *thd) return (thd->variables.sql_mode & MODE_INVALID_DATES); } -inline ulong sql_mode_for_dates() +inline ulonglong sql_mode_for_dates() { return sql_mode_for_dates(current_thd); } @@ -3566,12 +3683,18 @@ public: #ifdef WITH_ARIA_STORAGE_ENGINE #include <maria.h> +#else +#undef USE_ARIA_FOR_TMP_TABLES #endif #ifdef USE_ARIA_FOR_TMP_TABLES -#define ENGINE_COLUMNDEF MARIA_COLUMNDEF +#define TMP_ENGINE_COLUMNDEF MARIA_COLUMNDEF +#define TMP_ENGINE_HTON maria_hton +#define TMP_ENGINE_NAME "Aria" #else -#define ENGINE_COLUMNDEF MI_COLUMNDEF +#define TMP_ENGINE_COLUMNDEF MI_COLUMNDEF +#define TMP_ENGINE_HTON myisam_hton +#define TMP_ENGINE_NAME "MyISAM" #endif /* @@ -3594,7 +3717,7 @@ public: Copy_field *save_copy_field, *save_copy_field_end; uchar *group_buff; Item **items_to_copy; /* Fields in tmp table */ - ENGINE_COLUMNDEF *recinfo, *start_recinfo; + TMP_ENGINE_COLUMNDEF *recinfo, *start_recinfo; KEY *keyinfo; ha_rows end_write_records; /** @@ -3842,13 +3965,13 @@ public: /* Cost to materialize - execute the sub-join and write rows into temp.table */ - COST_VECT materialization_cost; + Cost_estimate materialization_cost; /* Cost to make one lookup in the temptable */ - COST_VECT lookup_cost; + Cost_estimate lookup_cost; /* Cost of scanning the materialized table */ - COST_VECT scan_cost; + Cost_estimate scan_cost; /* --- Execution structures ---------- */ @@ -4235,19 +4358,45 @@ public: #define CF_CAN_GENERATE_ROW_EVENTS (1U << 9) /** + Identifies statements which may deal with temporary tables and for which + temporary tables should be pre-opened to simplify privilege checks. +*/ +#define CF_PREOPEN_TMP_TABLES (1U << 10) + +/** + Identifies statements for which open handlers should be closed in the + beginning of the statement. +*/ +#define CF_HA_CLOSE (1U << 11) + +/** + Identifies statements that can be explained with EXPLAIN. +*/ +#define CF_CAN_BE_EXPLAINED (1U << 12) + +/** Identifies statements which may generate an optimizer trace */ +#define CF_OPTIMIZER_TRACE (1U << 14) + +/** + Identifies statements that should always be disallowed in + read only transactions. +*/ +#define CF_DISALLOW_IN_RO_TRANS (1U << 15) + +/** Statement that need the binlog format to be unchanged. */ -#define CF_FORCE_ORIGINAL_BINLOG_FORMAT (1U << 10) +#define CF_FORCE_ORIGINAL_BINLOG_FORMAT (1U << 16) /** Statement that inserts new rows (INSERT, REPLACE, LOAD, ALTER TABLE) */ -#define CF_INSERTS_DATA (1U << 11) +#define CF_INSERTS_DATA (1U << 17) /** Statement that updates existing rows (UPDATE, multi-update) */ -#define CF_UPDATES_DATA (1U << 12) +#define CF_UPDATES_DATA (1U << 18) /* Bits in server_command_flags */ @@ -4306,112 +4455,6 @@ inline void handler::decrement_statistics(ulong SSV::*offset) const status_var_decrement(table->in_use->status_var.*offset); } -inline int handler::ha_index_read_map(uchar * buf, const uchar * key, - key_part_map keypart_map, - enum ha_rkey_function find_flag) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_key_count); - int error= index_read_map(buf, key, keypart_map, find_flag); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - - -/* - @note: Other index lookup/navigation functions require prior - handler->index_init() call. This function is different, it requires - that the scan is not initialized, and accepts "uint index" as an argument. -*/ - -inline int handler::ha_index_read_idx_map(uchar * buf, uint index, - const uchar * key, - key_part_map keypart_map, - enum ha_rkey_function find_flag) -{ - DBUG_ASSERT(inited==NONE); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_key_count); - int error= index_read_idx_map(buf, index, key, keypart_map, find_flag); - if (!error) - { - update_rows_read(); - index_rows_read[index]++; - } - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_index_next(uchar * buf) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_next_count); - int error= index_next(buf); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_index_prev(uchar * buf) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_prev_count); - int error= index_prev(buf); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_index_first(uchar * buf) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_first_count); - int error= index_first(buf); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_index_last(uchar * buf) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_last_count); - int error= index_last(buf); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_index_next_same(uchar *buf, const uchar *key, - uint keylen) -{ - DBUG_ASSERT(inited==INDEX); - MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); - increment_statistics(&SSV::ha_read_next_count); - int error= index_next_same(buf, key, keylen); - if (!error) - update_index_statistics(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_INDEX_READ_ROW_DONE(error); - return error; -} inline int handler::ha_ft_read(uchar *buf) { @@ -4423,37 +4466,6 @@ inline int handler::ha_ft_read(uchar *buf) return error; } -inline int handler::ha_rnd_next(uchar *buf) -{ - MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, TRUE); - int error= rnd_next(buf); - if (!error) - { - update_rows_read(); - increment_statistics(&SSV::ha_read_rnd_next_count); - } - else if (error == HA_ERR_RECORD_DELETED) - increment_statistics(&SSV::ha_read_rnd_deleted_count); - else - increment_statistics(&SSV::ha_read_rnd_next_count); - - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_READ_ROW_DONE(error); - return error; -} - -inline int handler::ha_rnd_pos(uchar *buf, uchar *pos) -{ - MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, FALSE); - increment_statistics(&SSV::ha_read_rnd_count); - int error= rnd_pos(buf, pos); - if (!error) - update_rows_read(); - table->status=error ? STATUS_NOT_FOUND: 0; - MYSQL_READ_ROW_DONE(error); - return error; -} - inline int handler::ha_rnd_pos_by_record(uchar *buf) { int error= rnd_pos_by_record(buf); @@ -4474,24 +4486,73 @@ inline int handler::ha_read_first_row(uchar *buf, uint primary_key) 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); - int error= write_row(buf); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, + { error= write_row(buf); }) MYSQL_INSERT_ROW_DONE(error); return error; } 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); - int error= update_row(old_data, new_data); + MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, + { error= update_row(old_data, new_data);}) MYSQL_UPDATE_ROW_DONE(error); return error; } extern pthread_attr_t *get_connection_attrib(void); +/** + Set thread entering a condition + + This function should be called before putting a thread to wait for + a condition. @a mutex should be held before calling this + function. After being waken up, @f thd_exit_cond should be called. + + @param thd The thread entering the condition, NULL means current thread + @param cond The condition the thread is going to wait for + @param mutex The mutex associated with the condition, this must be + held before call this function + @param stage The new process message for the thread + @param old_stage The old process message for the thread + @param src_function The caller source function name + @param src_file The caller source file name + @param src_line The caller source line number +*/ +void thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, mysql_mutex_t *mutex, + const PSI_stage_info *stage, PSI_stage_info *old_stage, + const char *src_function, const char *src_file, + int src_line); + +#define THD_ENTER_COND(P1, P2, P3, P4, P5) \ + thd_enter_cond(P1, P2, P3, P4, P5, __func__, __FILE__, __LINE__) + +/** + Set thread leaving a condition + + This function should be called after a thread being waken up for a + condition. + + @param thd The thread entering the condition, NULL means current thread + @param stage The process message, ususally this should be the old process + message before calling @f thd_enter_cond + @param src_function The caller source function name + @param src_file The caller source file name + @param src_line The caller source line number +*/ +void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage, + const char *src_function, const char *src_file, + int src_line); + +#define THD_EXIT_COND(P1, P2) \ + thd_exit_cond(P1, P2, __func__, __FILE__, __LINE__) + #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h new file mode 100644 index 00000000000..5cf88d2566c --- /dev/null +++ b/sql/sql_cmd.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file Representation of an SQL command. +*/ + +#ifndef SQL_CMD_INCLUDED +#define SQL_CMD_INCLUDED + +/* + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... + + If the command returns a result set or is not allowed in stored + functions or triggers, please also make sure that + sp_get_flags_for_command (sp_head.cc) returns proper flags for the + added SQLCOM_. +*/ + +enum enum_sql_command { + SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE, + SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT, + SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX, + + 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_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, + SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, + SQLCOM_SHOW_TRIGGERS, + + SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, + SQLCOM_GRANT, + SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, + SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, + SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, + SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, + SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, + SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, + SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, + SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, + SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, + SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER, + SQLCOM_RENAME_TABLE, + SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, + SQLCOM_SHOW_OPEN_TABLES, + SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, + SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, + SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_DO, + SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, + SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, + SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER, + SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, + SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL, + SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION, + SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC, + SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC, + SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, + SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, + SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, + SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, + SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, + SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, + SQLCOM_ALTER_TABLESPACE, + SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN, + SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, + SQLCOM_SHOW_PLUGINS, + SQLCOM_SHOW_CONTRIBUTORS, + SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER, + SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, + SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, + SQLCOM_SHOW_CREATE_TRIGGER, + SQLCOM_ALTER_DB_UPGRADE, + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + SQLCOM_SIGNAL, SQLCOM_RESIGNAL, + SQLCOM_SHOW_RELAYLOG_EVENTS, + SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, + SQLCOM_SHOW_CLIENT_STATS, + SQLCOM_SLAVE_ALL_START, SQLCOM_SLAVE_ALL_STOP, + SQLCOM_SHOW_EXPLAIN, + + /* + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... + */ + /* This should be the last !!! */ + SQLCOM_END +}; + +/** + @class Sql_cmd - Representation of an SQL command. + + This class is an interface between the parser and the runtime. + The parser builds the appropriate derived classes of Sql_cmd + to represent a SQL statement in the parsed tree. + The execute() method in the derived classes of Sql_cmd contain the runtime + implementation. + Note that this interface is used for SQL statements recently implemented, + the code for older statements tend to load the LEX structure with more + attributes instead. + Implement new statements by sub-classing Sql_cmd, as this improves + code modularity (see the 'big switch' in dispatch_command()), and decreases + the total size of the LEX structure (therefore saving memory in stored + programs). + The recommended name of a derived class of Sql_cmd is Sql_cmd_<derived>. + + Notice that the Sql_cmd class should not be confused with the + Statement class. Statement is a class that is used to manage an SQL + command or a set of SQL commands. When the SQL statement text is + analyzed, the parser will create one or more Sql_cmd objects to + represent the actual SQL commands. +*/ +class Sql_cmd : public Sql_alloc +{ +private: + Sql_cmd(const Sql_cmd &); // No copy constructor wanted + void operator=(Sql_cmd &); // No assignment operator wanted + +public: + /** + @brief Return the command code for this statement + */ + virtual enum_sql_command sql_command_code() const = 0; + + /** + Execute this SQL statement. + @param thd the current thread. + @retval false on success. + @retval true on error + */ + virtual bool execute(THD *thd) = 0; + +protected: + Sql_cmd() + {} + + virtual ~Sql_cmd() + { + /* + Sql_cmd objects are allocated in thd->mem_root. + In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is + simply destroyed instead. + Do not rely on the destructor for any cleanup. + */ + DBUG_ASSERT(FALSE); + } +}; + +#endif // SQL_CMD_INCLUDED diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 9f6185280cd..59aa51916fb 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1109,7 +1109,7 @@ void prepare_new_connection_state(THD* thd) TODO: refactor this to avoid code duplication there */ thd->proc_info= 0; - thd->command= COM_SLEEP; + thd->set_command(COM_SLEEP); thd->set_time(); thd->init_for_queries(); @@ -1254,6 +1254,7 @@ void do_handle_one_connection(THD *thd_arg) { bool create_user= TRUE; + mysql_socket_set_thread_owner(thd->net.vio->mysql_socket); if (thd_prepare_connection(thd)) { create_user= FALSE; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index b8b979a282b..6a664e4d20b 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -97,6 +97,7 @@ public: int mysql_open_cursor(THD *thd, select_result *result, Server_side_cursor **pcursor) { + PSI_statement_locker *parent_locker; select_result *save_result; Select_materialize *result_materialize; LEX *lex= thd->lex; @@ -115,9 +116,12 @@ int mysql_open_cursor(THD *thd, select_result *result, &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 2); + parent_locker= thd->m_statement_psi; + thd->m_statement_psi= NULL; /* Mark that we can't use query cache with cursors */ thd->query_cache_is_applicable= 0; rc= mysql_execute_command(thd); + thd->m_statement_psi= parent_locker; MYSQL_QUERY_EXEC_DONE(rc); lex->result= save_result; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4bcb62ef764..d0a83eac189 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -88,7 +88,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); table->map=1; if (mysql_prepare_delete(thd, table_list, &conds)) @@ -228,7 +228,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* If running in safe sql mode, don't allow updates without keys */ if (table->quick_keys.is_clear_all()) { - thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + thd->set_status_no_index_used(); if (safe_update && !using_limit) { delete select; @@ -278,7 +278,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, &thd->lex->select_lex); DBUG_RETURN(TRUE); } - thd->examined_row_count+= examined_rows; + thd->inc_examined_row_count(examined_rows); /* Filesort has already found and selected the rows we want to delete, so we don't need the where clause @@ -309,7 +309,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, init_read_record_idx(&info, thd, table, 1, usable_index, reverse); init_ftfuncs(thd, select_lex, 1); - thd_proc_info(thd, "updating"); + THD_STAGE_INFO(thd, stage_updating); if (table->triggers && table->triggers->has_triggers(TRG_EVENT_DELETE, @@ -336,7 +336,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, update_virtual_fields(thd, table, table->triggers ? VCOL_UPDATE_ALL : VCOL_UPDATE_FOR_READ); - thd->examined_row_count++; + thd->inc_examined_row_count(1); // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) { @@ -393,7 +393,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->print_error(loc_error,MYF(0)); error=1; } - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); end_read_record(&info); if (options & OPTION_QUICK) (void) table->file->extra(HA_EXTRA_NORMAL); @@ -637,7 +637,7 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_ENTER("multi_delete::prepare"); unit= u; do_delete= 1; - thd_proc_info(thd, "deleting from main table"); + THD_STAGE_INFO(thd, stage_deleting_from_main_table); SELECT_LEX *select_lex= u->first_select(); if (select_lex->first_cond_optimization) { @@ -1027,7 +1027,7 @@ int multi_delete::do_table_deletes(TABLE *table, bool ignore) bool multi_delete::send_eof() { killed_state killed_status= NOT_KILLED; - thd_proc_info(thd, "deleting from reference tables"); + THD_STAGE_INFO(thd, stage_deleting_from_reference_tables); /* Does deletes for the last n - 1 tables, returns 0 if ok */ int local_error= do_deletes(); // returns 0 if success @@ -1036,7 +1036,7 @@ bool multi_delete::send_eof() local_error= local_error || error; killed_status= (local_error == 0)? NOT_KILLED : thd->killed; /* reset used flags */ - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; diff --git a/sql/sql_error.h b/sql/sql_error.h index f018387eb3b..fadd3b51ec6 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -20,6 +20,8 @@ #include "m_string.h" /* LEX_STRING */ #include "sql_string.h" /* String */ #include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ +#include "my_time.h" /* MYSQL_TIME */ +#include "decimal.h" class THD; @@ -191,6 +193,10 @@ public: MYSQL_ERROR::enum_warning_level get_level() const { return m_level; } + /** Destructor. */ + ~MYSQL_ERROR() + {} + private: /* The interface of MYSQL_ERROR is mostly private, by design, @@ -232,9 +238,7 @@ private: */ MYSQL_ERROR(MEM_ROOT *mem_root); - /** Destructor. */ - ~MYSQL_ERROR() - {} + /** Copy optional condition items attributes. @@ -319,6 +323,14 @@ private: MEM_ROOT *m_mem_root; }; +class Sql_condition : public MYSQL_ERROR +{ + /* + Wrapper class to allow one to use Sql_condition in handlers instead of + MYSQL_ERROR + */ +}; + /////////////////////////////////////////////////////////////////////////// /** diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 833e134bff9..09e4953cdc4 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -543,6 +543,13 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) DBUG_ENTER("open_and_lock_for_insert_delayed"); #ifndef EMBEDDED_LIBRARY + /* INSERT DELAYED is not allowed in a read only transaction. */ + if (thd->tx_read_only) + { + my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0)); + DBUG_RETURN(true); + } + /* In order for the deadlock detector to be able to find any deadlocks caused by the handler thread waiting for GRL or this table, we acquire @@ -733,7 +740,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, lock_type= table_list->lock_type; - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); thd->lex->used_tables=0; values= its++; value_count= values->elements; @@ -743,9 +750,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, FALSE, (fields.elements || !value_count || table_list->view != 0), - !ignore && (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)))) + !ignore && thd->is_strict_mode())) goto abort; /* mysql_prepare_insert set table_list->table if it was not set */ @@ -818,7 +823,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, #endif error=0; - thd_proc_info(thd, "update"); + THD_STAGE_INFO(thd, stage_update); if (duplic == DUP_REPLACE && (!table->triggers || !table->triggers->has_delete_triggers())) table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); @@ -857,9 +862,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } } - thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); + thd->abort_on_warning= !ignore && thd->is_strict_mode(); prepare_triggers_for_insert_stmt(table); @@ -1074,7 +1077,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); } - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); /* We'll report to the client this id: - if the table contains an autoincrement column and we successfully @@ -1995,7 +1998,7 @@ public: strmake(thd.security_ctx->priv_user, thd.security_ctx->user, USERNAME_LENGTH); thd.current_tablenr=0; - thd.command=COM_DELAYED_INSERT; + thd.set_command(COM_DELAYED_INSERT); thd.lex->current_select= 0; // for my_message_sql thd.lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock() /* @@ -2083,7 +2086,7 @@ I_List<Delayed_insert> delayed_threads; static Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { - thd_proc_info(thd, "waiting for delay_list"); + THD_STAGE_INFO(thd, stage_waiting_for_delay_list); mysql_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator<Delayed_insert> it(delayed_threads); Delayed_insert *di; @@ -2165,7 +2168,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); - thd_proc_info(thd, "Creating delayed handler"); + THD_STAGE_INFO(thd, stage_creating_delayed_handler); mysql_mutex_lock(&LOCK_delayed_create); /* The first search above was done without LOCK_delayed_create. @@ -2226,14 +2229,14 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, handler thread has been properly initialized before exiting. Otherwise we risk doing clone_ticket() on a ticket that is no longer valid. */ - thd_proc_info(thd, "waiting for handler open"); + THD_STAGE_INFO(thd, stage_waiting_for_handler_open); while (!di->handler_thread_initialized || (!di->thd.killed && !di->table && !thd->killed)) { mysql_cond_wait(&di->cond_client, &di->mutex); } mysql_mutex_unlock(&di->mutex); - thd_proc_info(thd, "got old table"); + THD_STAGE_INFO(thd, stage_got_old_table); if (thd->killed) { di->unlock(); @@ -2313,13 +2316,13 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) tables_in_use++; if (!thd.lock) // Table is not locked { - thd_proc_info(client_thd, "waiting for handler lock"); + THD_STAGE_INFO(client_thd, stage_waiting_for_handler_lock); mysql_cond_signal(&cond); // Tell handler to lock table while (!thd.killed && !thd.lock && ! client_thd->killed) { mysql_cond_wait(&cond_client, &mutex); } - thd_proc_info(client_thd, "got handler lock"); + THD_STAGE_INFO(client_thd, stage_got_handler_lock); if (client_thd->killed) goto error; if (thd.killed) @@ -2353,7 +2356,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) bytes. Since the table copy is used for creating one record only, the other record buffers and alignment are unnecessary. */ - thd_proc_info(client_thd, "allocating local table"); + THD_STAGE_INFO(client_thd, stage_allocating_local_table); copy_tmp= (char*) client_thd->alloc(sizeof(*copy)+ (share->fields+1)*sizeof(Field**)+ share->reclength + @@ -2480,11 +2483,11 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, DBUG_PRINT("enter", ("query = '%s' length %lu", query.str, (ulong) query.length)); - thd_proc_info(thd, "waiting for handler insert"); + THD_STAGE_INFO(thd, stage_waiting_for_handler_insert); mysql_mutex_lock(&di->mutex); while (di->stacked_inserts >= delayed_queue_size && !thd->killed) mysql_cond_wait(&di->cond_client, &di->mutex); - thd_proc_info(thd, "storing row into queue"); + THD_STAGE_INFO(thd, stage_storing_row_into_queue); if (thd->killed) goto err; @@ -2850,7 +2853,7 @@ pthread_handler_t handle_delayed_insert(void *arg) di->thd.mysys_var->current_cond= &di->cond; mysql_mutex_unlock(&di->thd.mysys_var->mutex); mysql_mutex_lock(&di->mutex); - thd_proc_info(&(di->thd), "Waiting for INSERT"); + THD_STAGE_INFO(&(di->thd), stage_waiting_for_insert); DBUG_PRINT("info",("Waiting for someone to insert rows")); while (!thd->killed && !di->status) @@ -2877,7 +2880,6 @@ pthread_handler_t handle_delayed_insert(void *arg) mysql_mutex_unlock(&di->thd.mysys_var->mutex); mysql_mutex_lock(&di->mutex); } - thd_proc_info(&(di->thd), 0); if (di->tables_in_use && ! thd->lock && !thd->killed) { @@ -3008,7 +3010,7 @@ bool Delayed_insert::handle_inserts(void) table->next_number_field=table->found_next_number_field; table->use_all_columns(); - thd_proc_info(&thd, "upgrading lock"); + THD_STAGE_INFO(&thd, stage_upgrading_lock); if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock, thd.variables.lock_wait_timeout)) { @@ -3022,7 +3024,7 @@ bool Delayed_insert::handle_inserts(void) goto err; } - thd_proc_info(&thd, "insert"); + THD_STAGE_INFO(&thd, stage_insert); max_rows= delayed_insert_limit; if (thd.killed || table->s->has_old_version()) { @@ -3159,7 +3161,7 @@ bool Delayed_insert::handle_inserts(void) { if (tables_in_use) mysql_cond_broadcast(&cond_client); // If waiting clients - thd_proc_info(&thd, "reschedule"); + THD_STAGE_INFO(&thd, stage_reschedule); mysql_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { @@ -3182,13 +3184,12 @@ bool Delayed_insert::handle_inserts(void) if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); mysql_mutex_lock(&mutex); - thd_proc_info(&thd, "insert"); + THD_STAGE_INFO(&thd, stage_insert); } if (tables_in_use) mysql_cond_broadcast(&cond_client); // If waiting clients } } - thd_proc_info(&thd, 0); mysql_mutex_unlock(&mutex); /* @@ -3363,9 +3364,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (!res && fields->elements) { bool saved_abort_on_warning= thd->abort_on_warning; - thd->abort_on_warning= !info.ignore && (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)); + thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); res= check_that_all_fields_are_given_values(thd, table_list->table, table_list); thd->abort_on_warning= saved_abort_on_warning; @@ -3480,10 +3479,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); if (info.handle_duplicates == DUP_UPDATE) table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); - thd->abort_on_warning= (!info.ignore && - (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); + thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); res= (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)); @@ -4101,10 +4097,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); if (thd->locked_tables_mode <= LTM_LOCK_TABLES) table->file->ha_start_bulk_insert((ha_rows) 0); - thd->abort_on_warning= (!info.ignore && - (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); + thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); if (check_that_all_fields_are_given_values(thd, table, table_list)) DBUG_RETURN(1); table->mark_columns_needed_for_insert(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b8ce3b6720e..82cdd4ead7b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -975,6 +975,7 @@ int MYSQLlex(void *arg, void *yythd) lip->lookahead_token= -1; *yylval= *(lip->lookahead_yylval); lip->lookahead_yylval= NULL; + lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, token, yylval); return token; } @@ -992,8 +993,12 @@ int MYSQLlex(void *arg, void *yythd) token= lex_one_token(arg, yythd); switch(token) { case CUBE_SYM: + lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH_CUBE_SYM, + yylval); return WITH_CUBE_SYM; case ROLLUP_SYM: + lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH_ROLLUP_SYM, + yylval); return WITH_ROLLUP_SYM; default: /* @@ -1002,6 +1007,7 @@ int MYSQLlex(void *arg, void *yythd) lip->lookahead_yylval= lip->yylval; lip->yylval= NULL; lip->lookahead_token= token; + lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH, yylval); return WITH; } break; @@ -1009,6 +1015,7 @@ int MYSQLlex(void *arg, void *yythd) break; } + lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, token, yylval); return token; } @@ -2593,7 +2600,8 @@ bool LEX::can_be_merged() if (tmp_unit->first_select()->parent_lex == this && (tmp_unit->item == 0 || (tmp_unit->item->place() != IN_WHERE && - tmp_unit->item->place() != IN_ON))) + tmp_unit->item->place() != IN_ON && + tmp_unit->item->place() != SELECT_LIST))) { selects_allow_merge= 0; break; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index be7cdd8ca1d..cc117e18d1e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -25,6 +25,7 @@ #include "item.h" /* From item_subselect.h: subselect_union_engine */ #include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */ #include "mem_root_array.h" +#include "sql_cmd.h" /* YACC and LEX Definitions */ @@ -123,87 +124,6 @@ struct sys_var_with_base #endif #endif -/* - When a command is added here, be sure it's also added in mysqld.cc - in "struct show_var_st status_vars[]= {" ... - - If the command returns a result set or is not allowed in stored - functions or triggers, please also make sure that - sp_get_flags_for_command (sp_head.cc) returns proper flags for the - added SQLCOM_. -*/ - -enum enum_sql_command { - SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE, - SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT, - SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX, - - 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_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, - SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, - SQLCOM_SHOW_TRIGGERS, - - SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, - SQLCOM_GRANT, - SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, - SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, - SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, - SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, - SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, - SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, - SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, - SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, - SQLCOM_SLAVE_START, SQLCOM_SLAVE_ALL_START, - SQLCOM_SLAVE_STOP, SQLCOM_SLAVE_ALL_STOP, - SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER, - SQLCOM_RENAME_TABLE, - SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, - SQLCOM_SHOW_OPEN_TABLES, - SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, - SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, - SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_DO, - SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, - SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, - SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER, - SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, - SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL, - SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION, - SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC, - SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC, - SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, - SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, - SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, - SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, - SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, - SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, - SQLCOM_ALTER_TABLESPACE, - SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN, - SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, - SQLCOM_SHOW_PLUGINS, - SQLCOM_SHOW_CONTRIBUTORS, - SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER, - SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, - SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, - SQLCOM_SHOW_CREATE_TRIGGER, - SQLCOM_ALTER_DB_UPGRADE, - SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, - SQLCOM_SIGNAL, SQLCOM_RESIGNAL, - SQLCOM_SHOW_RELAYLOG_EVENTS, - SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, - SQLCOM_SHOW_CLIENT_STATS, - SQLCOM_SHOW_EXPLAIN, - - /* - When a command is added here, be sure it's also added in mysqld.cc - in "struct show_var_st status_vars[]= {" ... - */ - /* This should be the last !!! */ - SQLCOM_END -}; - // describe/explain types #define DESCRIBE_NORMAL 1 #define DESCRIBE_EXTENDED 2 @@ -287,6 +207,7 @@ struct LEX_MASTER_INFO DYNAMIC_ARRAY repl_ignore_server_ids; char *host, *user, *password, *log_file_name; char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; + char *ssl_crl, *ssl_crlpath; char *relay_log_name; LEX_STRING connection_name; ulonglong pos; @@ -2285,6 +2206,11 @@ public: NOTE: this member must be used within MYSQLlex() function only. */ CHARSET_INFO *m_underscore_cs; + + /** + Current statement digest instrumentation. + */ + PSI_digest_locker* m_digest_psi; }; /** diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 6a4712ca5b5..11e23b56f71 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -474,10 +474,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->file->ha_start_bulk_insert((ha_rows) 0); table->copy_blobs=1; - thd->abort_on_warning= (!ignore && - (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); + thd->abort_on_warning= !ignore && thd->is_strict_mode(); thd_progress_init(thd, 2); if (ex->filetype == FILETYPE_XML) /* load xml */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0abb249d97b..f1362674d0c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -96,6 +96,7 @@ #include "probes_mysql.h" #include "set_var.h" #include "log_slow.h" +#include "sql_bootstrap.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -293,26 +294,60 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_UPDATES_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_UPDATES_DATA; sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_UPDATES_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_UPDATES_DATA; sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_INSERTS_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_INSERTS_DATA; sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_INSERTS_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_INSERTS_DATA; sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED; sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED;; sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_INSERTS_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_INSERTS_DATA;; sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS | CF_INSERTS_DATA; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED | + CF_INSERTS_DATA; sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS; - sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE | + CF_CAN_BE_EXPLAINED; + // (1) so that subquery is traced when doing "SET @var = (subquery)" + /* + @todo SQLCOM_SET_OPTION should have CF_CAN_GENERATE_ROW_EVENTS + set, because it may invoke a stored function that generates row + events. /Sven + */ + sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | + CF_AUTO_COMMIT_TRANS | + CF_OPTIMIZER_TRACE; // (1) + // (1) so that subquery is traced when doing "DO @var := (subquery)" sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE; // (1) sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; @@ -369,6 +404,12 @@ void init_update_queries(void) sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA; + /* + @todo SQLCOM_CREATE_FUNCTION should have CF_AUTO_COMMIT_TRANS + set. this currently is binlogged *before* the transaction if + executed inside a transaction because it does not have an implicit + pre-commit and is written to the statement cache. /Sven + */ sql_command_flags[SQLCOM_CREATE_FUNCTION]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; @@ -385,8 +426,13 @@ void init_update_queries(void) last called (or executed) statement is preserved. See mysql_execute_command() for how CF_ROW_COUNT is used. */ + /* + (1): without it, in "CALL some_proc((subq))", subquery would not be + traced. + */ sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_OPTIMIZER_TRACE; // (1) sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS; /* @@ -427,6 +473,104 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; + + /* + The following statements can deal with temporary tables, + so temporary tables should be pre-opened for those statements to + simplify privilege checking. + + There are other statements that deal with temporary tables and open + them, but which are not listed here. The thing is that the order of + pre-opening temporary tables for those statements is somewhat custom. + */ + sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_LOAD]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DROP_INDEX]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_UPDATE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CHECK]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_OPTIMIZE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_REPAIR]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES; + + /* + DDL statements that should start with closing opened handlers. + + We use this flag only for statements for which open HANDLERs + have to be closed before emporary tables are pre-opened. + */ + sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_OPTIMIZE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ANALYZE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CHECK]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_INDEX]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_HA_CLOSE; + + /* + Mark statements that always are disallowed in read-only + transactions. Note that according to the SQL standard, + even temporary table DDL should be disallowed. + */ + sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_VIEW]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_EVENT]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_SERVER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_SERVER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_SPFUNCTION]|=CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_TRUNCATE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_TABLESPACE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_REPAIR]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_OPTIMIZE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_GRANT]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_REVOKE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_REVOKE_ALL]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_INSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS; } bool sqlcom_can_generate_row_events(const THD *thd) @@ -479,7 +623,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, thd->profiling.set_query_source(buf, len); #endif - thd_proc_info(thd, "Execution of init_command"); + THD_STAGE_INFO(thd, stage_execution_of_init_command); save_client_capabilities= thd->client_capabilities; thd->client_capabilities|= CLIENT_MULTI_QUERIES; /* @@ -498,11 +642,19 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, } +static char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error) +{ + MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input); + char *line= mysql_file_fgets(buffer, size, in); + if (error) + *error= (line == NULL) ? ferror(in->m_file) : 0; + return line; +} + + static void handle_bootstrap_impl(THD *thd) { MYSQL_FILE *file= bootstrap_file; - char *buff, *res; - DBUG_ENTER("handle_bootstrap"); #ifndef EMBEDDED_LIBRARY @@ -510,7 +662,6 @@ static void handle_bootstrap_impl(THD *thd) thd->thread_stack= (char*) &thd; #endif /* EMBEDDED_LIBRARY */ - thd_proc_info(thd, 0); thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=0; /* @@ -520,50 +671,58 @@ static void handle_bootstrap_impl(THD *thd) */ thd->client_capabilities|= CLIENT_MULTI_RESULTS; - buff= (char*) thd->net.buff; thd->init_for_queries(); - while (mysql_file_fgets(buff, thd->net.max_packet, file)) + + for ( ; ; ) { + char buffer[MAX_BOOTSTRAP_QUERY_SIZE] = ""; + int rc, length; char *query; - /* strlen() can't be deleted because mysql_file_fgets() doesn't return length */ - ulong length= (ulong) strlen(buff); - while (buff[length-1] != '\n' && !mysql_file_feof(file)) + int error= 0; + + rc= read_bootstrap_query(buffer, &length, file, fgets_fn, &error); + + if (rc == READ_BOOTSTRAP_EOF) + break; + /* + Check for bootstrap file errors. SQL syntax errors will be + caught below. + */ + if (rc != READ_BOOTSTRAP_SUCCESS) { /* - We got only a part of the current string. Will try to increase - net buffer then read the rest of the current string. + mysql_parse() may have set a successful error status for the previous + query. We must clear the error status to report the bootstrap error. */ - /* purecov: begin tested */ - if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) + thd->get_stmt_da()->reset_diagnostics_area(); + + /* Get the nearest query text for reference. */ + char *err_ptr= buffer + (length <= MAX_BOOTSTRAP_ERROR_LEN ? + 0 : (length - MAX_BOOTSTRAP_ERROR_LEN)); + switch (rc) { - thd->protocol->end_statement(); - bootstrap_error= 1; + case READ_BOOTSTRAP_ERROR: + my_printf_error(ER_UNKNOWN_ERROR, "Bootstrap file error, return code (%d). " + "Nearest query: '%s'", MYF(0), error, err_ptr); break; - } - buff= (char*) thd->net.buff; - res= mysql_file_fgets(buff + length, thd->net.max_packet - length, file); - if (!res && !mysql_file_feof(file)) - { - thd->protocol->end_statement(); - bootstrap_error= 1; + + case READ_BOOTSTRAP_QUERY_SIZE: + my_printf_error(ER_UNKNOWN_ERROR, "Boostrap file error. Query size " + "exceeded %d bytes near '%s'.", MYF(0), + MAX_BOOTSTRAP_LINE_SIZE, err_ptr); break; - } - length+= (ulong) strlen(buff + length); - /* purecov: end */ - } - if (bootstrap_error) - break; /* purecov: inspected */ - while (length && (my_isspace(thd->charset(), buff[length-1]) || - buff[length-1] == ';')) - length--; - buff[length]=0; + default: + DBUG_ASSERT(false); + break; + } - /* Skip lines starting with delimiter */ - if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0) - continue; + thd->protocol->end_statement(); + bootstrap_error= 1; + break; + } - query= (char *) thd->memdup_w_gap(buff, length + 1, + query= (char *) thd->memdup_w_gap(buffer, length + 1, thd->db_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE); @@ -752,18 +911,32 @@ bool do_command(THD *thd) */ DEBUG_SYNC(thd, "before_do_command_net_read"); - if ((packet_length= my_net_read(net)) == packet_error) + thd->m_server_idle= TRUE; + packet_length= my_net_read(net); + thd->m_server_idle= FALSE; + + if ((packet_length == packet_error)) { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, vio_description(net->vio))); + /* Instrument this broken statement as "statement/com/error" */ + thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + com_statement_info[COM_END]. + m_key); + + /* Check if we can continue without closing the connection */ /* The error must be set. */ DBUG_ASSERT(thd->is_error()); thd->protocol->end_statement(); + /* Mark the statement completed. */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + if (net->error != 3) { return_value= TRUE; // We have to close it. @@ -809,6 +982,8 @@ bool do_command(THD *thd) return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); out: + /* The statement instrumentation must be closed in all cases. */ + DBUG_ASSERT(thd->m_statement_psi == NULL); DBUG_RETURN(return_value); } #endif /* EMBEDDED_LIBRARY */ @@ -921,7 +1096,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { DBUG_PRINT("crash_dispatch_command_before", ("now")); DBUG_ABORT(); }); - thd->command=command; + /* Performance Schema Interface instrumentation, begin */ + thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + com_statement_info[command]. + m_key); + thd->set_command(command); + /* Commands which always take a long time are logged into the slow log only if opt_log_slow_admin_statements is set. @@ -1076,6 +1256,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #if defined(ENABLED_PROFILING) thd->profiling.set_query_source(thd->query(), thd->query_length()); #endif + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), + thd->query_length()); + Parser_state parser_state; if (parser_state.init(thd, thd->query(), thd->query_length())) break; @@ -1109,6 +1292,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, length--; } + /* PSI end */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + + /* DTRACE end */ if (MYSQL_QUERY_DONE_ENABLED()) { MYSQL_QUERY_DONE(thd->is_error()); @@ -1120,11 +1308,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->profiling.set_query_source(beginning_of_next_stmt, length); #endif + /* DTRACE begin */ MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id, (char *) (thd->db ? thd->db : ""), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip); + /* PSI begin */ + thd->m_statement_psi= + MYSQL_START_STATEMENT(&thd->m_statement_state, + com_statement_info[command].m_key, + thd->db, thd->db_length); + THD_STAGE_INFO(thd, stage_init); + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt, + length); + thd->set_query_and_id(beginning_of_next_stmt, length, thd->charset(), next_query_id()); /* @@ -1474,12 +1672,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd, log_slow_statement(thd); - thd_proc_info(thd, "cleaning up"); + THD_STAGE_INFO(thd, stage_cleaning_up); thd->reset_query(); - thd->examined_row_count= 0; // For processlist - thd->command=COM_SLEEP; + thd->set_examined_row_count(0); // For processlist + thd->set_command(COM_SLEEP); + + /* Performance Schema Interface instrumentation, end */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + dec_thread_running(); - thd_proc_info(thd, 0); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); @@ -1525,7 +1727,7 @@ void log_slow_statement(THD *thd) (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && opt_log_queries_not_using_indexes && !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && - thd->examined_row_count >= thd->variables.min_examined_row_limit) + thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; /* @@ -1536,10 +1738,9 @@ void log_slow_statement(THD *thd) (global_query_id % thd->variables.log_slow_rate_limit) != 0) DBUG_VOID_RETURN; - thd_proc_info(thd, "logging slow query"); + THD_STAGE_INFO(thd, stage_logging_slow_query); slow_log_print(thd, thd->query(), thd->query_length(), thd->utime_after_query); - thd_proc_info(thd, 0); } DBUG_VOID_RETURN; } @@ -2171,6 +2372,19 @@ mysql_execute_command(THD *thd) DEBUG_SYNC(thd,"before_execute_sql_command"); #endif + /* + Check if we are in a read-only transaction and we're trying to + execute a statement which should always be disallowed in such cases. + + Note that this check is done after any implicit commits. + */ + if (thd->tx_read_only && + (sql_command_flags[lex->sql_command] & CF_DISALLOW_IN_RO_TRANS)) + { + my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0)); + goto error; + } + switch (lex->sql_command) { case SQLCOM_SHOW_EVENTS: @@ -3223,7 +3437,7 @@ end_with_restore_list: if (add_item_to_list(thd, new Item_null())) goto error; - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) break; @@ -3937,12 +4151,13 @@ end_with_restore_list: if (tx_chain) { if (trans_begin(thd)) - goto error; + goto error; } else { - /* Reset the isolation level if no chaining transaction. */ + /* Reset the isolation level and access mode if no chaining transaction.*/ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; } /* Disconnect the current client connection. */ if (tx_release) @@ -3974,8 +4189,9 @@ end_with_restore_list: } else { - /* Reset the isolation level if no chaining transaction. */ + /* Reset the isolation level and access mode if no chaining transaction.*/ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; } /* Disconnect the current client connection. */ if (tx_release) @@ -4493,9 +4709,10 @@ create_sp_error: thd->mdl_context.release_transactional_locks(); /* We've just done a commit, reset transaction - isolation level to the session default. + isolation level and access mode to the session default. */ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; my_ok(thd); break; case SQLCOM_XA_ROLLBACK: @@ -4504,9 +4721,10 @@ create_sp_error: thd->mdl_context.release_transactional_locks(); /* We've just done a rollback, reset transaction - isolation level to the session default. + isolation level and access mode to the session default. */ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; my_ok(thd); break; case SQLCOM_XA_RECOVER: @@ -4622,7 +4840,7 @@ create_sp_error: my_ok(thd); break; } - thd_proc_info(thd, "query end"); + THD_STAGE_INFO(thd, stage_query_end); thd->update_stats(); /* @@ -4682,9 +4900,8 @@ finish: lex->unit.cleanup(); /* Free tables */ - thd_proc_info(thd, "closing tables"); + THD_STAGE_INFO(thd, stage_closing_tables); close_thread_tables(thd); - thd_proc_info(thd, 0); #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt) @@ -4790,9 +5007,9 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) } } /* Count number of empty select queries */ - if (!thd->sent_row_count) + if (!thd->get_sent_row_count()) status_var_increment(thd->status_var.empty_queries); - status_var_add(thd->status_var.rows_sent, thd->sent_row_count); + status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); return res; } @@ -5009,7 +5226,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, dummy= 0; } - thd_proc_info(thd, "checking permissions"); + THD_STAGE_INFO(thd, stage_checking_permissions); if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { DBUG_PRINT("error",("No database")); @@ -5630,7 +5847,7 @@ void THD::reset_for_next_command(bool calculate_userstat) thd->stmt_da->reset_diagnostics_area(); thd->warning_info->reset_for_next_command(); thd->rand_used= 0; - thd->sent_row_count= thd->examined_row_count= 0; + thd->m_sent_row_count= thd->m_examined_row_count= 0; thd->accessed_rows_and_keys= 0; /* Copy data for user stats */ @@ -5859,6 +6076,10 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, if (!err) { + thd->m_statement_psi= + MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + sql_statement_info[thd->lex->sql_command]. + m_key); #ifndef NO_EMBEDDED_ACCESS_CHECKS if (mqh_used && thd->user_connect && check_mqh(thd, lex->sql_command)) @@ -5907,13 +6128,17 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, } else { + /* Instrument this broken statement as "statement/sql/error" */ + thd->m_statement_psi= + MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + sql_statement_info[SQLCOM_END].m_key); DBUG_ASSERT(thd->is_error()); DBUG_PRINT("info",("Command aborted. Fatal_error: %d", thd->is_fatal_error)); query_cache_abort(&thd->query_cache_tls); } - thd_proc_info(thd, "freeing items"); + THD_STAGE_INFO(thd, stage_freeing_items); sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); thd->end_statement(); @@ -5924,6 +6149,9 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, { /* Update statistics for getting the query from the cache */ thd->lex->sql_command= SQLCOM_SELECT; + thd->m_statement_psi= + MYSQL_REFINE_STATEMENT(thd->m_statement_psi, + sql_statement_info[SQLCOM_SELECT].m_key); } DBUG_VOID_RETURN; } @@ -6751,7 +6979,7 @@ THD *find_thread_by_id(ulong id) I_List_iterator<THD> it(threads); while ((tmp=it++)) { - if (tmp->command == COM_DAEMON) + if (tmp->get_command() == COM_DAEMON) continue; if (tmp->thread_id == id) { @@ -6853,7 +7081,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, I_List_iterator<THD> it(threads); while ((tmp=it++)) { - if (tmp->command == COM_DAEMON) + if (tmp->get_command() == COM_DAEMON) continue; /* Check that hostname (if given) and user name matches. @@ -7792,6 +8020,12 @@ bool parse_sql(THD *thd, thd->m_parser_state= parser_state; +#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE + /* Start Digest */ + thd->m_parser_state->m_lip.m_digest_psi= + MYSQL_DIGEST_START(thd->m_statement_psi); +#endif + /* Parse the query. */ bool mysql_parse_status= MYSQLparse(thd) != 0; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 1c47991f474..8778713d7e7 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -51,8 +51,8 @@ static TYPELIB global_plugin_typelib= { array_elements(global_plugin_typelib_names)-1, "", global_plugin_typelib_names, NULL }; - -char *opt_plugin_load= NULL; +static I_List<i_string> opt_plugin_load_list; +I_List<i_string> *opt_plugin_load_list_ptr= &opt_plugin_load_list; char *opt_plugin_dir_ptr; char opt_plugin_dir[FN_REFLEN]; ulong plugin_maturity; @@ -1040,7 +1040,7 @@ static bool plugin_add(MEM_ROOT *tmp_root, { struct st_plugin_int tmp; struct st_maria_plugin *plugin; - uint oks= 0, errs= 0; + uint oks= 0, errs= 0, dupes= 0; DBUG_ENTER("plugin_add"); DBUG_PRINT("enter", ("name: %s dl: %s", name->str, dl->str)); @@ -1069,51 +1069,54 @@ static bool plugin_add(MEM_ROOT *tmp_root, continue; // plugin name doesn't match if (!name->str && plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)) + { + dupes++; continue; // already installed + } - struct st_plugin_int *tmp_plugin_ptr; - if (*(int*)plugin->info < - min_plugin_info_interface_version[plugin->type] || - ((*(int*)plugin->info) >> 8) > - (cur_plugin_info_interface_version[plugin->type] >> 8)) - { - char buf[256]; - strxnmov(buf, sizeof(buf) - 1, "API version for ", - plugin_type_names[plugin->type].str, - " plugin ", tmp.name.str, - " not supported by this version of the server", NullS); - report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); - goto err; - } - if (plugin_maturity_map[plugin->maturity] < plugin_maturity) - { - char buf[256]; - strxnmov(buf, sizeof(buf) - 1, "Loading of ", - plugin_maturity_names[plugin->maturity], - " plugin ", tmp.name.str, - " is prohibited by --plugin-maturity=", - plugin_maturity_names[plugin_maturity], - NullS); - report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); - goto err; - } - tmp.plugin= plugin; - tmp.ref_count= 0; - tmp.state= PLUGIN_IS_UNINITIALIZED; - tmp.load_option= PLUGIN_ON; - if (test_plugin_options(tmp_root, &tmp, argc, argv)) - tmp.state= PLUGIN_IS_DISABLED; - - if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) - { - mysql_del_sys_var_chain(tmp.system_vars); - restore_pluginvar_names(tmp.system_vars); - goto err; - } - plugin_array_version++; - 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, 4096, 4096, MYF(0)); + struct st_plugin_int *tmp_plugin_ptr; + if (*(int*)plugin->info < + min_plugin_info_interface_version[plugin->type] || + ((*(int*)plugin->info) >> 8) > + (cur_plugin_info_interface_version[plugin->type] >> 8)) + { + char buf[256]; + strxnmov(buf, sizeof(buf) - 1, "API version for ", + plugin_type_names[plugin->type].str, + " plugin ", tmp.name.str, + " not supported by this version of the server", NullS); + report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); + goto err; + } + if (plugin_maturity_map[plugin->maturity] < plugin_maturity) + { + char buf[256]; + strxnmov(buf, sizeof(buf) - 1, "Loading of ", + plugin_maturity_names[plugin->maturity], + " plugin ", tmp.name.str, + " is prohibited by --plugin-maturity=", + plugin_maturity_names[plugin_maturity], + NullS); + report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); + goto err; + } + tmp.plugin= plugin; + tmp.ref_count= 0; + tmp.state= PLUGIN_IS_UNINITIALIZED; + tmp.load_option= PLUGIN_ON; + if (test_plugin_options(tmp_root, &tmp, argc, argv)) + tmp.state= PLUGIN_IS_DISABLED; + + if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) + { + mysql_del_sys_var_chain(tmp.system_vars); + restore_pluginvar_names(tmp.system_vars); + goto err; + } + plugin_array_version++; + 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, 4096, 4096, MYF(0)); if (name->str) DBUG_RETURN(FALSE); // all done @@ -1128,11 +1131,13 @@ err: break; } - if (errs == 0 && oks == 0) // no plugin was found + DBUG_ASSERT(!name->str || !dupes); // dupes is ONLY for name->str == 0 + + if (errs == 0 && oks == 0 && !dupes) // no plugin was found report_error(report, ER_CANT_FIND_DL_ENTRY, name->str); plugin_dl_del(dl); - DBUG_RETURN(errs > 0 || oks == 0); + DBUG_RETURN(errs > 0 || oks + dupes == 0); } @@ -1625,8 +1630,11 @@ int plugin_init(int *argc, char **argv, int flags) /* Register all dynamic plugins */ if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING)) { - if (opt_plugin_load) - plugin_load_list(&tmp_root, argc, argv, opt_plugin_load); + I_List_iterator<i_string> iter(opt_plugin_load_list); + i_string *item; + while (NULL != (item= iter++)) + plugin_load_list(&tmp_root, argc, argv, item->ptr); + if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE)) plugin_load(&tmp_root, argc, argv); } diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index be1cfcdcc4f..dc713826fe2 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -40,6 +40,7 @@ enum enum_plugin_load_option { PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE, extern const char *global_plugin_typelib_names[]; #include <my_sys.h> +#include "sql_list.h" #ifdef DBUG_OFF #define plugin_ref_to_int(A) A @@ -137,7 +138,7 @@ typedef struct st_plugin_int **plugin_ref; typedef int (*plugin_type_init)(struct st_plugin_int *); -extern char *opt_plugin_load; +extern I_List<i_string> *opt_plugin_load_list_ptr; extern char *opt_plugin_dir_ptr; extern char opt_plugin_dir[FN_REFLEN]; extern const LEX_STRING plugin_type_names[]; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 71b4a0cf817..025ff8820e6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2835,7 +2835,7 @@ void mysqld_stmt_reset(THD *thd, char *packet) stmt->state= Query_arena::STMT_PREPARED; - general_log_print(thd, thd->command, NullS); + general_log_print(thd, thd->get_command(), NullS); my_ok(thd); @@ -2868,7 +2868,7 @@ void mysqld_stmt_close(THD *thd, char *packet) */ DBUG_ASSERT(! stmt->is_in_use()); stmt->deallocate(); - general_log_print(thd, thd->command, NullS); + general_log_print(thd, thd->get_command(), NullS); DBUG_VOID_RETURN; } @@ -2983,7 +2983,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) thd->stmt_da= save_stmt_da; thd->warning_info= save_warinig_info; - general_log_print(thd, thd->command, NullS); + general_log_print(thd, thd->get_command(), NullS); DBUG_VOID_RETURN; } @@ -3093,6 +3093,7 @@ Execute_sql_statement(LEX_STRING sql_text) bool Execute_sql_statement::execute_server_code(THD *thd) { + PSI_statement_locker *parent_locker; bool error; if (alloc_query(thd, m_sql_text.str, m_sql_text.length)) @@ -3112,7 +3113,10 @@ Execute_sql_statement::execute_server_code(THD *thd) thd->lex->set_trg_event_type_for_tables(); + parent_locker= thd->m_statement_psi; + thd->m_statement_psi= NULL; error= mysql_execute_command(thd); + thd->m_statement_psi= parent_locker; /* report error issued during command execution */ if (error == 0 && thd->spcont == NULL) @@ -3898,13 +3902,17 @@ 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, (char *) (thd->db ? thd->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); } } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 6b8d0f5153f..917f4ea1a80 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -654,7 +654,7 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags, return NULL; } - thd_proc_info(thd, "Sending binlog event to slave"); + THD_STAGE_INFO(thd, stage_sending_binlog_event_to_slave); pos= my_b_tell(log); if (RUN_HOOK(binlog_transmit, before_send_event, @@ -1112,7 +1112,7 @@ impossible position"; #ifndef DBUG_OFF ulong hb_info_counter= 0; #endif - const char* old_msg= thd->proc_info; + PSI_stage_info old_stage; signal_cnt= mysql_bin_log.signal_cnt; do { @@ -1121,9 +1121,9 @@ impossible position"; DBUG_ASSERT(heartbeat_ts); set_timespec_nsec(*heartbeat_ts, heartbeat_period); } - thd->enter_cond(log_cond, log_lock, - "Master has sent all binlog to slave; " - "waiting for binlog to be updated"); + thd->ENTER_COND(log_cond, log_lock, + &stage_master_has_sent_all_binlog_to_slave, + &old_stage); ret= mysql_bin_log.wait_for_update_bin_log(thd, heartbeat_ts); DBUG_ASSERT(ret == 0 || (heartbeat_period != 0)); if (ret == ETIMEDOUT || ret == ETIME) @@ -1140,14 +1140,14 @@ impossible position"; /* reset transmit packet for the heartbeat event */ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) { - thd->exit_cond(old_msg); + thd->EXIT_COND(&old_stage); goto err; } if (send_heartbeat_event(net, packet, p_coord, current_checksum_alg)) { errmsg = "Failed on my_net_write()"; my_errno= ER_UNKNOWN_ERROR; - thd->exit_cond(old_msg); + thd->EXIT_COND(&old_stage); goto err; } } @@ -1156,7 +1156,7 @@ impossible position"; DBUG_PRINT("wait",("binary log received update or a broadcast signal caught")); } } while (signal_cnt == mysql_bin_log.signal_cnt && !thd->killed); - thd->exit_cond(old_msg); + thd->EXIT_COND(&old_stage); } break; @@ -1185,7 +1185,7 @@ impossible position"; bool loop_breaker = 0; /* need this to break out of the for loop from switch */ - thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); + THD_STAGE_INFO(thd, stage_finished_reading_one_binlog_switching_to_next_binlog); switch (mysql_bin_log.find_next_log(&linfo, 1)) { case 0: break; @@ -1238,7 +1238,7 @@ end: RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); my_eof(thd); - thd_proc_info(thd, "Waiting to finalize termination"); + THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination); mysql_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; mysql_mutex_unlock(&LOCK_thread_count); @@ -1246,7 +1246,7 @@ end: DBUG_VOID_RETURN; err: - thd_proc_info(thd, "Waiting to finalize termination"); + THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination); if (my_errno == ER_MASTER_FATAL_ERROR_READING_BINLOG && my_b_inited(&log)) { /* @@ -1460,7 +1460,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) DBUG_RETURN(-1); - thd_proc_info(thd, "Killing slave"); + THD_STAGE_INFO(thd, stage_killing_slave); int thread_mask; lock_slave_threads(mi); // Get a mask of _running_ threads @@ -1487,7 +1487,6 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) ER(ER_SLAVE_WAS_NOT_RUNNING)); } unlock_slave_threads(mi); - thd_proc_info(thd, 0); if (slave_errno) { @@ -1622,7 +1621,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) while ((tmp=it++)) { - if (tmp->command == COM_BINLOG_DUMP && + if (tmp->get_command() == COM_BINLOG_DUMP && tmp->server_id == slave_server_id) { mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete @@ -1727,7 +1726,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) goto err; } - thd_proc_info(thd, "Changing master"); + THD_STAGE_INFO(thd, stage_changing_master); create_logfile_name_with_suffix(master_info_file_tmp, sizeof(master_info_file_tmp), @@ -1867,10 +1866,15 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1); if (lex_mi->ssl_key) strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1); + if (lex_mi->ssl_crl) + strmake(mi->ssl_crl, lex_mi->ssl_crl, sizeof(mi->ssl_crl)-1); + if (lex_mi->ssl_crlpath) + strmake(mi->ssl_crlpath, lex_mi->ssl_crlpath, sizeof(mi->ssl_crlpath)-1); + #ifndef HAVE_OPENSSL if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath || lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key || - lex_mi->ssl_verify_server_cert ) + lex_mi->ssl_verify_server_cert || lex_mi->ssl_crl || lex_mi->ssl_crlpath) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS)); #endif @@ -1935,7 +1939,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) if (need_relay_log_purge) { relay_log_purge= 1; - thd_proc_info(thd, "Purging old relay logs"); + THD_STAGE_INFO(thd, stage_purging_old_relay_logs); if (purge_relay_logs(&mi->rli, thd, 0 /* not only reset, but also reinit */, &errmsg)) @@ -2006,7 +2010,6 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) err: unlock_slave_threads(mi); - thd_proc_info(thd, 0); if (ret == FALSE) my_ok(thd); DBUG_RETURN(ret); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 41c0b07bc49..27b93cff189 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -65,8 +65,6 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "index_merge", "hash_ALL", "hash_range", "hash_index", "hash_index_merge" }; -const char *copy_to_tmp_table= "Copying to tmp table"; - struct st_sargable_param; static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); @@ -151,9 +149,6 @@ static COND *optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value, COND_EQUAL **cond_equal); bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); -static bool create_internal_tmp_table_from_heap2(THD *, TABLE *, - ENGINE_COLUMNDEF *, ENGINE_COLUMNDEF **, - int, bool, handlerton *, const char *); static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, Procedure *proc); @@ -1025,7 +1020,7 @@ JOIN::optimize_inner() optimized= 1; DEBUG_SYNC(thd, "before_join_optimize"); - thd_proc_info(thd, "optimizing"); + THD_STAGE_INFO(thd, stage_optimizing); set_allowed_join_cache_types(); need_distinct= TRUE; @@ -1265,7 +1260,7 @@ JOIN::optimize_inner() sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables); /* Calculate how to do the join */ - thd_proc_info(thd, "statistics"); + THD_STAGE_INFO(thd, stage_statistics); if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || thd->is_fatal_error) { @@ -1290,7 +1285,7 @@ JOIN::optimize_inner() select_distinct= select_distinct && (const_tables != table_count); } - thd_proc_info(thd, "preparing"); + THD_STAGE_INFO(thd, stage_preparing); if (result->initialize_tables(this)) { DBUG_PRINT("error",("Error: initialize_tables() failed")); @@ -1866,7 +1861,7 @@ int JOIN::init_execution() if (need_tmp) { DBUG_PRINT("info",("Creating tmp table")); - thd_proc_info(thd, "Creating tmp table"); + THD_STAGE_INFO(thd, stage_copying_to_tmp_table); init_items_ref_array(); @@ -1911,7 +1906,7 @@ int JOIN::init_execution() if (group_list && simple_group) { DBUG_PRINT("info",("Sorting for group")); - thd_proc_info(thd, "Sorting for group"); + THD_STAGE_INFO(thd, stage_sorting_for_group); if (create_sort_index(thd, this, group_list, HA_POS_ERROR, HA_POS_ERROR, FALSE) || alloc_group_fields(this, group_list) || @@ -1935,7 +1930,7 @@ int JOIN::init_execution() if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { DBUG_PRINT("info",("Sorting for order")); - thd_proc_info(thd, "Sorting for order"); + THD_STAGE_INFO(thd, stage_sorting_for_order); if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR, TRUE)) { @@ -2290,7 +2285,7 @@ void JOIN::exec_inner() const bool has_group_by= this->group; - thd_proc_info(thd, "executing"); + THD_STAGE_INFO(thd, stage_executing); error= 0; if (procedure) { @@ -2298,7 +2293,8 @@ void JOIN::exec_inner() if (procedure->change_columns(procedure_fields_list) || result->prepare(procedure_fields_list, unit)) { - thd->limit_found_rows= thd->examined_row_count= 0; + thd->set_examined_row_count(0); + thd->limit_found_rows= 0; DBUG_VOID_RETURN; } columns_list= &procedure_fields_list; @@ -2339,7 +2335,7 @@ void JOIN::exec_inner() { error= (int) result->send_eof(); send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 : - thd->sent_row_count); + thd->get_sent_row_count()); } } else @@ -2350,7 +2346,7 @@ void JOIN::exec_inner() } /* Single select (without union) always returns 0 or 1 row */ thd->limit_found_rows= send_records; - thd->examined_row_count= 0; + thd->set_examined_row_count(0); DBUG_VOID_RETURN; } /* @@ -2487,7 +2483,7 @@ void JOIN::exec_inner() curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ - thd_proc_info(thd, copy_to_tmp_table); + THD_STAGE_INFO(thd, stage_copying_to_tmp_table); DBUG_PRINT("info", ("%s", thd->proc_info)); if (!curr_join->sort_and_group && curr_join->const_tables != curr_join->table_count) @@ -2637,7 +2633,7 @@ void JOIN::exec_inner() DBUG_VOID_RETURN; } DBUG_PRINT("info",("Sorting for index")); - thd_proc_info(thd, "Creating sort index"); + THD_STAGE_INFO(thd, stage_creating_sort_index); if (create_sort_index(thd, curr_join, curr_join->group_list, HA_POS_ERROR, HA_POS_ERROR, FALSE) || make_group_fields(this, curr_join)) @@ -2647,7 +2643,7 @@ void JOIN::exec_inner() sortorder= curr_join->sortorder; } - thd_proc_info(thd, "Copying to group table"); + THD_STAGE_INFO(thd, stage_copying_to_group_table); DBUG_PRINT("info", ("%s", thd->proc_info)); if (curr_join != this) { @@ -2732,7 +2728,7 @@ void JOIN::exec_inner() if (curr_join->select_distinct && ! curr_join->group_list) { - thd_proc_info(thd, "Removing duplicates"); + THD_STAGE_INFO(thd, stage_removing_duplicates); if (remove_duplicates(curr_join, curr_tmp_table, *curr_fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; @@ -2803,7 +2799,7 @@ void JOIN::exec_inner() if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_result_set_metadata")); - thd_proc_info(thd, "Sorting result"); + THD_STAGE_INFO(thd, stage_sorting_result); /* If we have already done the group, add HAVING to sorted table */ if (curr_join->tmp_having && ! curr_join->group_list && ! curr_join->sort_and_group) @@ -2960,7 +2956,7 @@ void JOIN::exec_inner() curr_join->fields= curr_fields_list; curr_join->procedure= procedure; - thd_proc_info(thd, "Sending data"); + THD_STAGE_INFO(thd, stage_sending_data); DBUG_PRINT("info", ("%s", thd->proc_info)); result->send_result_set_metadata((procedure ? curr_join->procedure_fields_list : *curr_fields_list), @@ -2977,9 +2973,9 @@ void JOIN::exec_inner() } /* Accumulate the counts from all join iterations of all join parts. */ - thd->examined_row_count+= curr_join->examined_rows; + thd->inc_examined_row_count(curr_join->examined_rows); DBUG_PRINT("counts", ("thd->examined_row_count: %lu", - (ulong) thd->examined_row_count)); + (ulong) thd->get_examined_row_count())); /* With EXPLAIN EXTENDED we have to restore original ref_array @@ -3169,7 +3165,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, if (!(join= new JOIN(thd, fields, select_options, result))) DBUG_RETURN(TRUE); - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); thd->lex->used_tables=0; if ((err= join->prepare(rref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc_param, @@ -3204,7 +3200,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, err: if (free_join) { - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); err|= select_lex->cleanup(); DBUG_RETURN(err || thd->is_error()); } @@ -6798,7 +6794,7 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables, double JOIN::get_examined_rows() { - ha_rows examined_rows; + double examined_rows; double prev_fanout= 1; JOIN_TAB *tab= first_breadth_first_tab(this, WALK_OPTIMIZATION_TABS); JOIN_TAB *prev_tab= tab; @@ -6808,7 +6804,7 @@ double JOIN::get_examined_rows() while ((tab= next_breadth_first_tab(this, WALK_OPTIMIZATION_TABS, tab))) { prev_fanout *= prev_tab->records_read; - examined_rows+= (ha_rows) (tab->get_examined_rows() * prev_fanout); + examined_rows+= tab->get_examined_rows() * prev_fanout; prev_tab= tab; } return examined_rows; @@ -7713,7 +7709,8 @@ get_best_combination(JOIN *join) sub-order */ SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info; - j->records= j->records_read= (ha_rows)(sjm->is_sj_scan? sjm->rows : 1); + j->records_read= sjm->is_sj_scan? sjm->rows : 1; + j->records= (ha_rows) j->records_read; JOIN_TAB *jt; JOIN_TAB_RANGE *jt_range; if (!(jt= (JOIN_TAB*)join->thd->alloc(sizeof(JOIN_TAB)*sjm->tables)) || @@ -7776,7 +7773,7 @@ get_best_combination(JOIN *join) Save records_read in JOIN_TAB so that select_describe()/etc don't have to access join->best_positions[]. */ - j->records_read= (ha_rows)join->best_positions[tablenr].records_read; + j->records_read= join->best_positions[tablenr].records_read; join->map2table[j->table->tablenr]= j; /* If we've reached the end of sjm nest, switch back to main sequence */ @@ -9748,7 +9745,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, uint table_index, JOIN_TAB *prev_tab) { - COST_VECT cost; + Cost_estimate cost; uint flags= 0; ha_rows rows= 0; uint bufsz= 4096; @@ -10212,10 +10209,10 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) /* These init changes read_record */ if (tab->use_quick == 2) { - join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED; + join->thd->set_status_no_good_index_used(); tab->read_first_record= join_init_quick_read_record; if (statistics) - status_var_increment(join->thd->status_var.select_range_check_count); + join->thd->inc_status_select_range_check(); } else { @@ -10226,14 +10223,14 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) if (tab->select && tab->select->quick) { if (statistics) - status_var_increment(join->thd->status_var.select_range_count); + join->thd->inc_status_select_range(); } else { - join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + join->thd->set_status_no_index_used(); if (statistics) { - status_var_increment(join->thd->status_var.select_scan_count); + join->thd->inc_status_select_scan(); join->thd->query_plan_flags|= QPLAN_FULL_SCAN; } } @@ -10243,16 +10240,14 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) if (tab->select && tab->select->quick) { if (statistics) - status_var_increment(join->thd->status_var. - select_full_range_join_count); + join->thd->inc_status_select_full_range_join(); } else { - join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + join->thd->set_status_no_index_used(); if (statistics) { - status_var_increment(join->thd->status_var. - select_full_join_count); + join->thd->inc_status_select_full_join(); join->thd->query_plan_flags|= QPLAN_FULL_JOIN; } } @@ -10480,7 +10475,7 @@ double JOIN_TAB::scan_time() ha_rows JOIN_TAB::get_examined_rows() { - ha_rows examined_rows; + double examined_rows; if (select && select->quick && use_quick != 2) examined_rows= select->quick->records; @@ -10510,7 +10505,7 @@ ha_rows JOIN_TAB::get_examined_rows() } } else - examined_rows= (ha_rows) records_read; + examined_rows= records_read; return examined_rows; } @@ -11219,7 +11214,8 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables, result->send_eof(); // Should be safe } /* Update results for FOUND_ROWS */ - join->thd->limit_found_rows= join->thd->examined_row_count= 0; + join->thd->limit_found_rows= 0; + join->thd->set_examined_row_count(0); DBUG_RETURN(0); } @@ -14292,7 +14288,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, KEY *keyinfo; KEY_PART_INFO *key_part_info; Item **copy_func; - ENGINE_COLUMNDEF *recinfo; + TMP_ENGINE_COLUMNDEF *recinfo; /* total_uneven_bit_length is uneven bit length for visible fields hidden_uneven_bit_length is uneven bit length for hidden fields @@ -14307,7 +14303,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, (int) distinct, (int) save_sum_fields, (ulong) rows_limit,test(group))); - status_var_increment(thd->status_var.created_tmp_tables); + thd->inc_status_created_tmp_tables(); thd->query_plan_flags|= QPLAN_TMP_TABLE; if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) @@ -15267,8 +15263,7 @@ bool open_tmp_table(TABLE *table) } -#if defined(WITH_ARIA_STORAGE_ENGINE) && defined(USE_ARIA_FOR_TMP_TABLES) - +#ifdef USE_ARIA_FOR_TMP_TABLES /* Create internal (MyISAM or Maria) temporary table @@ -15284,12 +15279,12 @@ bool open_tmp_table(TABLE *table) Create an internal emporary table according to passed description. The is assumed to have one unique index or constraint. - The passed array or ENGINE_COLUMNDEF structures must have this form: + The passed array or TMP_ENGINE_COLUMNDEF structures must have this form: 1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte when there are many nullable columns) 2. Table columns - 3. One free ENGINE_COLUMNDEF element (*recinfo points here) + 3. One free TMP_ENGINE_COLUMNDEF element (*recinfo points here) This function may use the free element to create hash column for unique constraint. @@ -15301,8 +15296,8 @@ bool open_tmp_table(TABLE *table) bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options, my_bool big_tables) { int error; @@ -15427,7 +15422,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, table->db_stat=0; goto err; } - status_var_increment(table->in_use->status_var.created_tmp_disk_tables); + table->in_use->inc_status_created_tmp_disk_tables(); table->in_use->query_plan_flags|= QPLAN_TMP_DISK; share->db_record_offset= 1; DBUG_RETURN(0); @@ -15435,20 +15430,6 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, DBUG_RETURN(1); } - -bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, - int error, - bool ignore_last_dupp_key_error) -{ - return create_internal_tmp_table_from_heap2(thd, table, - start_recinfo, recinfo, error, - ignore_last_dupp_key_error, - maria_hton, - "converting HEAP to Aria"); -} - #else /* @@ -15466,12 +15447,12 @@ bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, Create an internal emporary table according to passed description. The is assumed to have one unique index or constraint. - The passed array or ENGINE_COLUMNDEF structures must have this form: + The passed array or TMP_ENGINE_COLUMNDEF structures must have this form: 1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte when there are many nullable columns) 2. Table columns - 3. One free ENGINE_COLUMNDEF element (*recinfo points here) + 3. One free TMP_ENGINE_COLUMNDEF element (*recinfo points here) This function may use the free element to create hash column for unique constraint. @@ -15484,8 +15465,8 @@ bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, /* Create internal MyISAM temporary table */ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options, my_bool big_tables) { int error; @@ -15587,7 +15568,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, table->db_stat=0; goto err; } - status_var_increment(table->in_use->status_var.created_tmp_disk_tables); + table->in_use->inc_status_created_tmp_disk_tables(); table->in_use->query_plan_flags|= QPLAN_TMP_DISK; share->db_record_offset= 1; table->created= TRUE; @@ -15597,24 +15578,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, } -/** - If a HEAP table gets full, create a MyISAM table and copy all rows to this -*/ - -bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, - int error, - bool ignore_last_dupp_key_error) -{ - return create_internal_tmp_table_from_heap2(thd, table, - start_recinfo, recinfo, error, - ignore_last_dupp_key_error, - myisam_hton, - "converting HEAP to MyISAM"); -} - -#endif /* WITH_MARIA_STORAGE_ENGINE */ +#endif /* USE_ARIA_FOR_TMP_TABLES */ /* @@ -15623,20 +15587,18 @@ bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, */ -static bool -create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, - int error, - bool ignore_last_dupp_key_error, - handlerton *hton, - const char *proc_info) +bool +create_internal_tmp_table_from_heap(THD *thd, TABLE *table, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, + int error, + bool ignore_last_dupp_key_error) { TABLE new_table; TABLE_SHARE share; const char *save_proc_info; int write_err= 0; - DBUG_ENTER("create_internal_tmp_table_from_heap2"); + DBUG_ENTER("create_internal_tmp_table_from_heap"); if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL) @@ -15651,13 +15613,13 @@ create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, new_table= *table; share= *table->s; new_table.s= &share; - new_table.s->db_plugin= ha_lock_engine(thd, hton); + new_table.s->db_plugin= ha_lock_engine(thd, TMP_ENGINE_HTON); if (!(new_table.file= get_new_handler(&share, &new_table.mem_root, new_table.s->db_type()))) DBUG_RETURN(1); // End of memory save_proc_info=thd->proc_info; - thd_proc_info(thd, proc_info); + THD_STAGE_INFO(thd, stage_converting_heap_to_myisam); new_table.no_rows= table->no_rows; if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo, @@ -15724,8 +15686,8 @@ create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, table->file->change_table_ptr(table, table->s); table->use_all_columns(); if (save_proc_info) - thd_proc_info(thd, save_proc_info == copy_to_tmp_table ? - "Copying to tmp table on disk" : save_proc_info); + thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ? + "Copying to tmp table on disk" : save_proc_info)); DBUG_RETURN(0); err: @@ -15753,7 +15715,7 @@ free_tmp_table(THD *thd, TABLE *entry) DBUG_PRINT("enter",("table: %s",entry->alias.c_ptr())); save_proc_info=thd->proc_info; - thd_proc_info(thd, "removing tmp table"); + THD_STAGE_INFO(thd, stage_removing_tmp_table); if (entry->file && entry->created) { @@ -22027,7 +21989,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, } else { - ha_rows examined_rows= tab->get_examined_rows(); + double examined_rows= tab->get_examined_rows(); item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows, MY_INT64_NUM_DECIMAL_DIGITS)); @@ -22037,7 +21999,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, { float f= 0.0; if (examined_rows) - f= (float) (100.0 * tab->records_read / examined_rows); + f= (100.0 * (float)tab->records_read) / examined_rows; set_if_smaller(f, 100.0); item_list.push_back(new Item_float(f, 2)); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 638de926d75..54aca3c4829 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -29,20 +29,11 @@ #endif #include "procedure.h" -#include <myisam.h> #include "sql_array.h" /* Array */ #include "records.h" /* READ_RECORD */ #include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */ -#if defined(WITH_ARIA_STORAGE_ENGINE) -#include <maria.h> -#endif -#if defined(USE_ARIA_FOR_TMP_TABLES) -#define TMP_ENGINE_HTON maria_hton -#else -#define TMP_ENGINE_HTON myisam_hton -#endif /* Values in optimize */ #define KEY_OPTIMIZE_EXISTS 1 #define KEY_OPTIMIZE_REF_OR_NULL 2 @@ -289,8 +280,8 @@ typedef struct st_join_table { */ double read_time; - /* psergey-todo: make the below have type double, like POSITION::records_read? */ - ha_rows records_read; + /* Copy of POSITION::records_read, set by get_best_combination() */ + double records_read; /* Startup cost for execution */ double startup_cost; @@ -770,7 +761,7 @@ typedef struct st_position :public Sql_alloc double read_time; /* Cumulative cost and record count for the join prefix */ - COST_VECT prefix_cost; + Cost_estimate prefix_cost; double prefix_record_count; /* @@ -1751,8 +1742,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool make_copy_field, uint convert_blob_length); bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options, my_bool big_tables); /* @@ -1819,12 +1810,12 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, const char* alias, bool do_not_open=FALSE); void free_tmp_table(THD *thd, TABLE *entry); bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, int error, bool ignore_last_dupp_key_error); bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, - ENGINE_COLUMNDEF *start_recinfo, - ENGINE_COLUMNDEF **recinfo, + TMP_ENGINE_COLUMNDEF *start_recinfo, + TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options, my_bool big_tables); bool open_tmp_table(TABLE *table); void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 095ad409a94..1f860fe23db 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2157,7 +2157,7 @@ static const char *thread_state_info(THD *tmp) { if (tmp->net.reading_or_writing == 2) return "Writing to net"; - else if (tmp->command == COM_SLEEP) + else if (tmp->get_command() == COM_SLEEP) return ""; else return "Reading from net"; @@ -2236,7 +2236,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) tmp_sctx->host ? tmp_sctx->host : ""); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); - thd_info->command=(int) tmp->command; + thd_info->command=(int) tmp->get_command(); mysql_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var)) mysql_mutex_lock(&mysys_var->mutex); @@ -2330,7 +2330,7 @@ void Show_explain_request::call_in_target_thread() */ target_thd->set_n_backup_active_arena((Query_arena*)request_thd, &backup_arena); - + query_str.copy(target_thd->query(), target_thd->query_length(), target_thd->query_charset()); @@ -2547,8 +2547,8 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) "Killed" : 0)))) table->field[4]->store(val, strlen(val), cs); else - table->field[4]->store(command_name[tmp->command].str, - command_name[tmp->command].length, cs); + table->field[4]->store(command_name[tmp->get_command()].str, + command_name[tmp->get_command()].length, cs); /* MYSQL_TIME */ const ulonglong utime= (tmp->start_time ? (unow.val - tmp->start_time * HRTIME_RESOLUTION - @@ -2601,7 +2601,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) sizeof(THD)), FALSE); table->field[12]->set_notnull(); - table->field[13]->store((longlong) tmp->examined_row_count, TRUE); + table->field[13]->store((longlong) tmp->get_examined_row_count(), TRUE); table->field[13]->set_notnull(); if (schema_table_store_record(thd, table)) @@ -6936,7 +6936,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) if (et.load_from_row(thd, event_table)) { - my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias.c_ptr()); + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event"); DBUG_RETURN(1); } diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index e671ad9526f..ed4d2c23d53 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -243,8 +243,7 @@ static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd, truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str); if (truncated) { - if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)) + if (thd->is_strict_mode()) { thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, name); DBUG_RETURN(1); @@ -348,8 +347,7 @@ int Signal_common::eval_signal_informations(THD *thd, MYSQL_ERROR *cond) & utf8_text, str); if (truncated) { - if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)) + if (thd->is_strict_mode()) { thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, "MESSAGE_TEXT"); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d0a4aedfa4f..3c094e1740e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1478,6 +1478,7 @@ void execute_ddl_log_recovery() THD *thd; DDL_LOG_ENTRY ddl_log_entry; char file_name[FN_REFLEN]; + static char recover_query_string[]= "INTERNAL DDL LOG RECOVER IN PROGRESS"; DBUG_ENTER("execute_ddl_log_recovery"); /* @@ -1497,6 +1498,9 @@ void execute_ddl_log_recovery() thd->thread_stack= (char*) &thd; thd->store_globals(); + thd->set_query(recover_query_string, strlen(recover_query_string)); + + /* this also initialize LOCK_gdl */ num_entries= read_ddl_log_header(); for (i= 1; i < num_entries + 1; i++) { @@ -2561,8 +2565,7 @@ bool check_duplicates_in_interval(const char *set_or_name, { THD *thd= current_thd; ErrConvString err(*cur_value, *cur_length, cs); - if ((current_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + if (current_thd->is_strict_mode()) { my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0), name, err.ptr(), set_or_name); @@ -3752,8 +3755,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (tmp_len < key->key_create_info.comment.length) { - if ((thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + if (thd->is_strict_mode()) { my_error(ER_TOO_LONG_INDEX_COMMENT, MYF(0), key_info->name, static_cast<ulong>(INDEX_COMMENT_MAXLEN)); @@ -3891,8 +3893,7 @@ static bool prepare_blob_field(THD *thd, Create_field *sql_field) /* Convert long VARCHAR columns to TEXT or BLOB */ char warn_buff[MYSQL_ERRMSG_SIZE]; - if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))) + if (sql_field->def || thd->is_strict_mode()) { my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, static_cast<ulong>(MAX_FIELD_VARCHARLENGTH / @@ -4422,7 +4423,7 @@ bool mysql_create_table_no_lock(THD *thd, } } - thd_proc_info(thd, "creating table"); + THD_STAGE_INFO(thd, stage_creating_table); #ifdef HAVE_READLINK { @@ -4538,7 +4539,7 @@ bool mysql_create_table_no_lock(THD *thd, error= FALSE; err: - thd_proc_info(thd, "After create"); + THD_STAGE_INFO(thd, stage_after_create); delete file; DBUG_RETURN(error); @@ -4729,6 +4730,20 @@ mysql_rename_table(handlerton *base, const char *old_db, my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE"); else if (error) my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error); + +#ifdef HAVE_PSI_TABLE_INTERFACE + /* + Remove the old table share from the pfs table share array. The new table + share will be created when the renamed table is first accessed. + */ + if (likely(error == 0)) + { + my_bool temp_table= (my_bool)is_prefix(old_name, tmp_file_prefix); + PSI_CALL(drop_table_share)(temp_table, old_db, strlen(old_db), + old_name, strlen(old_name)); + } +#endif + DBUG_RETURN(error != 0); } @@ -4924,7 +4939,7 @@ mysql_discard_or_import_tablespace(THD *thd, ALTER TABLE */ - thd_proc_info(thd, "discard_or_import_tablespace"); + THD_STAGE_INFO(thd, stage_discard_or_import_tablespace); discard= test(tablespace_op == DISCARD_TABLESPACE); @@ -4942,7 +4957,7 @@ mysql_discard_or_import_tablespace(THD *thd, error= table->file->ha_discard_or_import_tablespace(discard); - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); if (error) goto err; @@ -6134,7 +6149,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, to simplify further comparisions: we want to see if it's a RENAME later just by comparing the pointers, avoiding the need for strcmp. */ - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); table_name=table_list->table_name; alias= (lower_case_table_names == 2) ? table_list->alias : table_name; db=table_list->db; @@ -6342,7 +6357,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; } - thd_proc_info(thd, "setup"); + THD_STAGE_INFO(thd, stage_setup); if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { @@ -6375,7 +6390,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!error && (new_name != table_name || new_db != db)) { - thd_proc_info(thd, "rename"); + THD_STAGE_INFO(thd, stage_rename); /* Then do a 'simple' rename of the table. First we need to close all instances of 'source' table. @@ -6896,7 +6911,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!table->s->tmp_table && need_lock_for_indexes && wait_while_table_is_used(thd, table, extra_func)) goto err_new_table_cleanup; - thd_proc_info(thd, "manage keys"); + THD_STAGE_INFO(thd, stage_manage_keys); DEBUG_SYNC(thd, "alter_table_manage_keys"); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); @@ -7108,7 +7123,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, (mysql_execute_command()) to release metadata locks. */ - thd_proc_info(thd, "rename result table"); + THD_STAGE_INFO(thd, stage_rename_result_table); my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix, current_pid, thd->thread_id); if (lower_case_table_names) @@ -7283,7 +7298,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (thd->locked_tables_list.reopen_tables(thd)) goto err_with_mdl; - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); DEBUG_SYNC(thd, "alter_table_before_main_binlog"); @@ -7479,9 +7494,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); /* We can abort alter table for any table type */ - thd->abort_on_warning= !ignore && test(thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)); + thd->abort_on_warning= !ignore && thd->is_strict_mode(); from->file->info(HA_STATUS_VARIABLE); to->file->ha_start_bulk_insert(from->file->stats.records, @@ -7549,7 +7562,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, tables.alias= tables.table_name= from->s->table_name.str; tables.db= from->s->db.str; - thd_proc_info(thd, "Sorting"); + THD_STAGE_INFO(thd, stage_sorting); if (thd->lex->select_lex.setup_ref_array(thd, order_num) || setup_order(thd, thd->lex->select_lex.ref_pointer_array, &tables, fields, all_fields, order) || @@ -7564,7 +7577,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, thd_progress_next_stage(thd); } - thd_proc_info(thd, "copy to tmp table"); + 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(); to->mark_virtual_columns_for_write(TRUE); @@ -7666,7 +7679,7 @@ err: free_io_cache(from); delete [] copy; - thd_proc_info(thd, "Enabling keys"); + THD_STAGE_INFO(thd, stage_enabling_keys); thd_progress_next_stage(thd); if (error > 0) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index eb4454ecab3..106c134223e 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -672,8 +672,8 @@ bool st_select_lex_unit::exec() 0); if (!saved_error) { - examined_rows+= thd->examined_row_count; - thd->examined_row_count= 0; + examined_rows+= thd->get_examined_row_count(); + thd->set_examined_row_count(0); if (union_result->flush()) { thd->lex->current_select= lex_select_save; @@ -817,7 +817,7 @@ bool st_select_lex_unit::exec() if (!saved_error) { thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows; - thd->examined_row_count+= examined_rows; + thd->inc_examined_row_count(examined_rows); } /* Mark for slow query log if any of the union parts didn't use diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 28b9fe7eacd..0d1cb7de5f2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -302,7 +302,7 @@ int mysql_update(THD *thd, if (table_list->handle_derived(thd->lex, DT_PREPARE)) DBUG_RETURN(1); - thd_proc_info(thd, "init"); + THD_STAGE_INFO(thd, stage_init); table= table_list->table; if (!table_list->single_table_updatable()) @@ -420,7 +420,7 @@ int mysql_update(THD *thd, /* If running in safe sql mode, don't allow updates without keys */ if (table->quick_keys.is_clear_all()) { - thd->server_status|=SERVER_QUERY_NO_INDEX_USED; + thd->set_status_no_index_used(); if (safe_update && !using_limit) { my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, @@ -471,10 +471,8 @@ int mysql_update(THD *thd, We can't update table directly; We must first search after all matching rows before updating the table! */ - - // Verify that table->restore_column_maps_after_mark_index() will work - DBUG_ASSERT(table->read_set == &table->def_read_set); - DBUG_ASSERT(table->write_set == &table->def_write_set); + MY_BITMAP *save_read_set= table->read_set; + MY_BITMAP *save_write_set= table->write_set; if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) table->add_read_columns_used_by_index(used_index); @@ -506,7 +504,7 @@ int mysql_update(THD *thd, { goto err; } - thd->examined_row_count+= examined_rows; + thd->inc_examined_row_count(examined_rows); /* Filesort has already found and selected the rows we want to update, so we don't need the where clause @@ -551,7 +549,7 @@ int mysql_update(THD *thd, else init_read_record_idx(&info, thd, table, 1, used_index, reverse); - thd_proc_info(thd, "Searching rows for update"); + THD_STAGE_INFO(thd, stage_searching_rows_for_update); ha_rows tmp_limit= limit; while (!(error=info.read_record(&info)) && !thd->killed) @@ -560,7 +558,7 @@ int mysql_update(THD *thd, update_virtual_fields(thd, table, table->triggers ? VCOL_UPDATE_ALL : VCOL_UPDATE_FOR_READ); - thd->examined_row_count++; + thd->inc_examined_row_count(1); if (!select || (error= select->skip_record(thd)) > 0) { if (table->file->was_semi_consistent_read()) @@ -616,11 +614,8 @@ int mysql_update(THD *thd, if (error >= 0) goto err; } - /* - This restore bitmaps, works for add_read_columns_used_by_index() and - use_all_columns(): - */ - table->restore_column_maps_after_mark_index(); + table->disable_keyread(); + table->column_bitmaps_set(save_read_set, save_write_set); } if (ignore) @@ -639,13 +634,10 @@ int mysql_update(THD *thd, */ thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - thd_proc_info(thd, "Updating"); + THD_STAGE_INFO(thd, stage_updating); transactional_table= table->file->has_transactions(); - thd->abort_on_warning= test(!ignore && - (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); + thd->abort_on_warning= !ignore && thd->is_strict_mode(); if (table->triggers && table->triggers->has_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER)) @@ -681,7 +673,7 @@ int mysql_update(THD *thd, update_virtual_fields(thd, table, table->triggers ? VCOL_UPDATE_ALL : VCOL_UPDATE_FOR_READ); - thd->examined_row_count++; + thd->inc_examined_row_count(1); if (!select || select->skip_record(thd) > 0) { if (table->file->was_semi_consistent_read()) @@ -886,7 +878,7 @@ int mysql_update(THD *thd, end_read_record(&info); delete select; - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); (void) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); /* @@ -1391,9 +1383,7 @@ bool mysql_multi_update(THD *thd, DBUG_RETURN(TRUE); } - thd->abort_on_warning= test(thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES)); + thd->abort_on_warning= thd->is_strict_mode(); List<Item> total_list; @@ -1449,7 +1439,7 @@ int multi_update::prepare(List<Item> ¬_used_values, thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - thd_proc_info(thd, "updating main table"); + THD_STAGE_INFO(thd, stage_updating_main_table); tables_to_update= get_table_map(fields); @@ -2277,7 +2267,7 @@ bool multi_update::send_eof() ulonglong id; killed_state killed_status= NOT_KILLED; DBUG_ENTER("multi_update::send_eof"); - thd_proc_info(thd, "updating reference tables"); + THD_STAGE_INFO(thd, stage_updating_reference_tables); /* Does updates for the last n - 1 tables, returns 0 if ok; @@ -2291,7 +2281,7 @@ bool multi_update::send_eof() later carried out killing should not affect binlogging. */ killed_status= (local_error == 0) ? NOT_KILLED : thd->killed; - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); /* We must invalidate the query cache before binlog writing and ha_autocommit_... */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index bbc5c324573..02f70c12ad2 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -724,7 +724,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_RETURN(0); err: - thd_proc_info(thd, "end"); + THD_STAGE_INFO(thd, stage_end); lex->link_first_table_back(view, link_to_local); unit->cleanup(); DBUG_RETURN(res || thd->is_error()); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9664aad1e19..56e7db96a1a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -731,6 +731,116 @@ static bool add_create_index (LEX *lex, Key::Keytype type, return FALSE; } + +/** + Create a separate LEX for each assignment if in SP. + + If we are in SP we want have own LEX for each assignment. + This is mostly because it is hard for several sp_instr_set + and sp_instr_set_trigger instructions share one LEX. + (Well, it is theoretically possible but adds some extra + overhead on preparation for execution stage and IMO less + robust). + + QQ: May be we should simply prohibit group assignments in SP? + + @see sp_create_assignment_instr + + @param thd Thread context + @param no_lookahead True if the parser has no lookahead +*/ + +static void sp_create_assignment_lex(THD *thd, bool no_lookahead) +{ + LEX *lex= thd->lex; + + if (lex->sphead) + { + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + LEX *old_lex= lex; + lex->sphead->reset_lex(thd); + lex= thd->lex; + + /* Set new LEX as if we at start of set rule. */ + lex->sql_command= SQLCOM_SET_OPTION; + mysql_init_select(lex); + lex->var_list.empty(); + lex->one_shot_set= 0; + lex->autocommit= 0; + /* get_ptr() is only correct with no lookahead. */ + DBUG_ASSERT(no_lookahead); + lex->sphead->m_tmp_query= lip->get_ptr(); + /* Inherit from outer lex. */ + lex->option_type= old_lex->option_type; + } +} + + +/** + Create a SP instruction for a SET assignment. + + @see sp_create_assignment_lex + + @param thd Thread context + @param no_lookahead True if the parser has no lookahead + + @return false if success, true otherwise. +*/ + +static bool sp_create_assignment_instr(THD *thd, bool no_lookahead) +{ + LEX *lex= thd->lex; + + if (lex->sphead) + { + sp_head *sp= lex->sphead; + + if (!lex->var_list.is_empty()) + { + /* + We have assignment to user or system variable or + option setting, so we should construct sp_instr_stmt + for it. + */ + LEX_STRING qbuff; + sp_instr_stmt *i; + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + + if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont, + lex))) + return true; + + /* + Extract the query statement from the tokenizer. The + end is either lip->ptr, if there was no lookahead, + lip->tok_end otherwise. + */ + if (no_lookahead) + qbuff.length= lip->get_ptr() - sp->m_tmp_query; + else + qbuff.length= lip->get_tok_end() - sp->m_tmp_query; + + if (!(qbuff.str= (char*) alloc_root(thd->mem_root, + qbuff.length + 5))) + return true; + + strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query, + qbuff.length); + qbuff.length+= 4; + i->m_query= qbuff; + if (sp->add_instr(i)) + return true; + } + enum_var_type inner_option_type= lex->option_type; + if (lex->sphead->restore_lex(thd)) + return true; + /* Copy option_type to outer lex in case it has changed. */ + thd->lex->option_type= inner_option_type; + } + return false; +} + + %} %union { int num; @@ -789,10 +899,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 174 shift/reduce conflicts. + Currently there are 171 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 174 +%expect 171 /* Comments for TOKENS. @@ -1104,6 +1214,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MASTER_SSL_CA_SYM %token MASTER_SSL_CERT_SYM %token MASTER_SSL_CIPHER_SYM +%token MASTER_SSL_CRL_SYM +%token MASTER_SSL_CRLPATH_SYM %token MASTER_SSL_KEY_SYM %token MASTER_SSL_SYM %token MASTER_SSL_VERIFY_SERVER_CERT_SYM @@ -1169,8 +1281,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OFFSET_SYM %token OLD_PASSWORD %token ON /* SQL-2003-R */ -%token ONE_SHOT_SYM %token ONE_SYM +%token ONLY_SYM /* SQL-2003-R */ %token ONLINE_SYM %token OPEN_SYM /* SQL-2003-R */ %token OPTIMIZE @@ -1475,8 +1587,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); table_option opt_if_not_exists opt_no_write_to_binlog opt_temporary all_or_any opt_distinct opt_ignore_leaves fulltext_options spatial_type union_option - start_transaction_opts field_def - union_opt select_derived_init option_type2 + field_def + union_opt select_derived_init transaction_access_mode_types opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt @@ -1484,6 +1596,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_time_precision kill_type kill_option int_num opt_default_time_precision +/* + Bit field of MYSQL_START_TRANS_OPT_* flags. +*/ +%type <num> opt_start_transaction_option_list +%type <num> start_transaction_option_list +%type <num> start_transaction_option + %type <m_yes_no_unk> opt_chain opt_release @@ -1616,7 +1735,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ref_list opt_match_clause opt_on_update_delete use opt_delete_options opt_delete_option varchar nchar nvarchar opt_outer table_list table_name table_alias_ref_list table_alias_ref - opt_option opt_place + opt_place opt_attribute opt_attribute_list attribute column_list column_list_id opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list @@ -1975,6 +2094,14 @@ master_def: Lex->mi.ssl_verify_server_cert= $3 ? LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } + | MASTER_SSL_CRL_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_crl= $3.str; + } + | MASTER_SSL_CRLPATH_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_crlpath= $3.str; + } | MASTER_HEARTBEAT_PERIOD_SYM EQ NUM_literal { @@ -7151,20 +7278,56 @@ slave: ; start: - START_SYM TRANSACTION_SYM start_transaction_opts + START_SYM TRANSACTION_SYM opt_start_transaction_option_list { LEX *lex= Lex; lex->sql_command= SQLCOM_BEGIN; + /* READ ONLY and READ WRITE are mutually exclusive. */ + if (($3 & MYSQL_START_TRANS_OPT_READ_WRITE) && + ($3 & MYSQL_START_TRANS_OPT_READ_ONLY)) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } lex->start_transaction_opt= $3; } ; -start_transaction_opts: - /*empty*/ { $$ = 0; } - | WITH CONSISTENT_SYM SNAPSHOT_SYM +opt_start_transaction_option_list: + /* empty */ + { + $$= 0; + } + | start_transaction_option_list + { + $$= $1; + } + ; + +start_transaction_option_list: + start_transaction_option + { + $$= $1; + } + | start_transaction_option_list ',' start_transaction_option + { + $$= $1 | $3; + } + ; + +start_transaction_option: + WITH CONSISTENT_SYM SNAPSHOT_SYM { $$= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT; } + | READ_SYM ONLY_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_ONLY; + } + | READ_SYM WRITE_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_WRITE; + } ; slave_thread_opts: @@ -13305,6 +13468,8 @@ keyword_sp: | MASTER_SSL_CAPATH_SYM {} | MASTER_SSL_CERT_SYM {} | MASTER_SSL_CIPHER_SYM {} + | MASTER_SSL_CRL_SYM {} + | MASTER_SSL_CRLPATH_SYM {} | MASTER_SSL_KEY_SYM {} | MAX_CONNECTIONS_PER_HOUR {} | MAX_QUERIES_PER_HOUR {} @@ -13340,9 +13505,9 @@ keyword_sp: | NVARCHAR_SYM {} | OFFSET_SYM {} | OLD_PASSWORD {} - | ONE_SHOT_SYM {} | ONE_SYM {} | ONLINE_SYM {} + | ONLY_SYM {} | PACK_KEYS_SYM {} | PAGE_SYM {} | PARTIAL {} @@ -13464,10 +13629,15 @@ keyword_sp: | VIA_SYM {} ; -/* Option functions */ +/* + SQLCOM_SET_OPTION statement. + + Note that to avoid shift/reduce conflicts, we have separate rules for the + first option listed in the statement. +*/ set: - SET opt_option + SET { LEX *lex=Lex; lex->sql_command= SQLCOM_SET_OPTION; @@ -13476,115 +13646,96 @@ set: lex->var_list.empty(); lex->one_shot_set= 0; lex->autocommit= 0; + sp_create_assignment_lex(YYTHD, yychar == YYEMPTY); } - option_value_list + start_option_value_list {} ; -opt_option: - /* empty */ {} - | OPTION {} - ; - -option_value_list: - option_type_value - | option_value_list ',' option_type_value - ; -option_type_value: +// Start of option value list +start_option_value_list: + option_value_no_option_type { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; - - if (lex->sphead) - { - /* - If we are in SP we want have own LEX for each assignment. - This is mostly because it is hard for several sp_instr_set - and sp_instr_set_trigger instructions share one LEX. - (Well, it is theoretically possible but adds some extra - overhead on preparation for execution stage and IMO less - robust). - - QQ: May be we should simply prohibit group assignments in SP? - */ - lex->sphead->reset_lex(thd); - lex= thd->lex; - - /* Set new LEX as if we at start of set rule. */ - lex->sql_command= SQLCOM_SET_OPTION; - mysql_init_select(lex); - lex->option_type=OPT_SESSION; - lex->var_list.empty(); - lex->one_shot_set= 0; - lex->autocommit= 0; - lex->sphead->m_tmp_query= lip->get_tok_start(); - } + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; } - ext_option_value + option_value_list_continued + | TRANSACTION_SYM { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; - - if (lex->sphead) - { - sp_head *sp= lex->sphead; + Lex->option_type= OPT_DEFAULT; + } + transaction_characteristics + { + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | option_type + { + Lex->option_type= $1; + } + start_option_value_list_following_option_type + ; - if (!lex->var_list.is_empty()) - { - /* - We have assignment to user or system variable or - option setting, so we should construct sp_instr_stmt - for it. - */ - LEX_STRING qbuff; - sp_instr_stmt *i; - if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont, - lex))) - MYSQL_YYABORT; +// Start of option value list, option_type was given +start_option_value_list_following_option_type: + option_value_following_option_type + { + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + option_value_list_continued + | TRANSACTION_SYM transaction_characteristics + { + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + ; - /* - Extract the query statement from the tokenizer. The - end is either lip->ptr, if there was no lookahead, - lip->tok_end otherwise. - */ - if (yychar == YYEMPTY) - qbuff.length= lip->get_ptr() - sp->m_tmp_query; - else - qbuff.length= lip->get_tok_end() - sp->m_tmp_query; +// Remainder of the option value list after first option value. +option_value_list_continued: + /* empty */ + | ',' option_value_list + ; - if (!(qbuff.str= (char*) alloc_root(thd->mem_root, - qbuff.length + 5))) - MYSQL_YYABORT; +// Repeating list of option values after first option value. +option_value_list: + { + sp_create_assignment_lex(YYTHD, yychar == YYEMPTY); + } + option_value + { + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | option_value_list ',' + { + sp_create_assignment_lex(YYTHD, yychar == YYEMPTY); + } + option_value + { + if (sp_create_assignment_instr(YYTHD, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + ; - strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query, - qbuff.length); - qbuff.length+= 4; - i->m_query= qbuff; - if (sp->add_instr(i)) - MYSQL_YYABORT; - } - if (lex->sphead->restore_lex(thd)) - MYSQL_YYABORT; - } +// Wrapper around option values following the first option value in the stmt. +option_value: + option_type + { + Lex->option_type= $1; } + option_value_following_option_type + | option_value_no_option_type ; option_type: - option_type2 {} - | GLOBAL_SYM { $$=OPT_GLOBAL; } + GLOBAL_SYM { $$=OPT_GLOBAL; } | LOCAL_SYM { $$=OPT_SESSION; } | SESSION_SYM { $$=OPT_SESSION; } ; -option_type2: - /* empty */ { $$= OPT_DEFAULT; } - | ONE_SHOT_SYM { Lex->one_shot_set= 1; $$= OPT_SESSION; } - ; - opt_var_type: /* empty */ { $$=OPT_SESSION; } | GLOBAL_SYM { $$=OPT_GLOBAL; } @@ -13599,74 +13750,62 @@ opt_var_ident_type: | SESSION_SYM '.' { $$=OPT_SESSION; } ; -ext_option_value: - sys_option_value - | option_type2 option_value +// Option values with preceeding option_type. +option_value_following_option_type: + internal_variable_name equal set_expr_or_default + { + THD *thd= YYTHD; + LEX *lex= Lex; + + if ($1.var && $1.var != trg_new_row_fake_var) + { + /* It is a system variable. */ + if (set_system_variable(thd, &$1, lex->option_type, $3)) + MYSQL_YYABORT; + } + else + { + /* + Not in trigger assigning value to new row, + and option_type preceeding local variable is illegal. + */ + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } + } ; -sys_option_value: - option_type internal_variable_name equal set_expr_or_default +// Option values without preceeding option_type. +option_value_no_option_type: + internal_variable_name equal set_expr_or_default { THD *thd= YYTHD; LEX *lex= Lex; - LEX_STRING *name= &$2.base_name; + LEX_STRING *name= &$1.base_name; - if ($2.var == trg_new_row_fake_var) + if ($1.var == trg_new_row_fake_var) { /* We are in trigger and assigning value to field of new row */ - if ($1) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - if (set_trigger_new_row(YYTHD, name, $4)) + if (set_trigger_new_row(YYTHD, name, $3)) MYSQL_YYABORT; } - else if ($2.var) + else if ($1.var) { - if ($1) - lex->option_type= $1; - /* It is a system variable. */ - if (set_system_variable(thd, &$2, lex->option_type, $4)) + if (set_system_variable(thd, &$1, lex->option_type, $3)) MYSQL_YYABORT; } else { sp_pcontext *spc= lex->spcont; - sp_variable_t *spv= spc->find_variable(name); - - if ($1) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } + sp_variable *spv= spc->find_variable(name, false); /* It is a local variable. */ - if (set_local_variable(thd, spv, $4)) + if (set_local_variable(thd, spv, $3)) MYSQL_YYABORT; } } - | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types - { - THD *thd= YYTHD; - LEX *lex=Lex; - lex->option_type= $1; - Item *item= new (thd->mem_root) Item_int((int32) $5); - if (item == NULL) - MYSQL_YYABORT; - set_var *var= new set_var(lex->option_type, - find_sys_var(thd, "tx_isolation"), - &null_lex_str, - item); - if (var == NULL) - MYSQL_YYABORT; - lex->var_list.push_back(var); - } - ; - -option_value: - '@' ident_or_text equal expr + | '@' ident_or_text equal expr { Item_func_set_user_var *item; item= new (YYTHD->mem_root) Item_func_set_user_var($2, $4); @@ -13712,7 +13851,7 @@ option_value: names.str= (char *)"names"; names.length= 5; - if (spc && spc->find_variable(&names)) + if (spc && spc->find_variable(&names, false)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); else my_parse_error(ER(ER_SYNTAX_ERROR)); @@ -13748,7 +13887,7 @@ option_value: pw.str= (char *)"password"; pw.length= 8; - if (spc && spc->find_variable(&pw)) + if (spc && spc->find_variable(&pw, false)) { my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); MYSQL_YYABORT; @@ -13757,6 +13896,7 @@ option_value: MYSQL_YYABORT; user->host=null_lex_str; user->user.str=thd->security_ctx->user; + user->user.length= strlen(thd->security_ctx->user); set_var_password *var= new set_var_password(user, $3); if (var == NULL) MYSQL_YYABORT; @@ -13861,6 +14001,54 @@ internal_variable_name: } ; +transaction_characteristics: + transaction_access_mode + | isolation_level + | transaction_access_mode ',' isolation_level + | isolation_level ',' transaction_access_mode + ; + +transaction_access_mode: + transaction_access_mode_types + { + THD *thd= YYTHD; + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int((int32) $1); + if (item == NULL) + MYSQL_YYABORT; + set_var *var= new set_var(lex->option_type, + find_sys_var(thd, "tx_read_only"), + &null_lex_str, + item); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); + } + ; + +isolation_level: + ISOLATION LEVEL_SYM isolation_types + { + THD *thd= YYTHD; + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int((int32) $3); + if (item == NULL) + MYSQL_YYABORT; + set_var *var= new set_var(lex->option_type, + find_sys_var(thd, "tx_isolation"), + &null_lex_str, + item); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); + } + ; + +transaction_access_mode_types: + READ_SYM ONLY_SYM { $$= true; } + | READ_SYM WRITE_SYM { $$= false; } + ; + isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } | READ_SYM COMMITTED_SYM { $$= ISO_READ_COMMITTED; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index d0b39f2b9b0..ed5e34463e9 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -14,7 +14,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* +/** + @file + Definitions of all server's session or global variables. + How to add new variables: 1. copy one of the existing variables, and edit the declaration. @@ -122,6 +125,22 @@ static Sys_var_ulong Sys_pfs_max_file_instances( CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), DEFAULT(PFS_MAX_FILE), BLOCK_SIZE(1)); +static Sys_var_ulong Sys_pfs_max_sockets( + "performance_schema_max_socket_instances", + "Maximum number of opened instrumented sockets.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_socket_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_MAX_SOCKETS), + 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)); + static Sys_var_ulong Sys_pfs_max_mutex_classes( "performance_schema_max_mutex_classes", "Maximum number of mutex instruments.", @@ -178,6 +197,111 @@ static Sys_var_ulong Sys_pfs_max_thread_instances( CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), DEFAULT(PFS_MAX_THREAD), BLOCK_SIZE(1)); +static Sys_var_ulong 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)); + +static Sys_var_ulong 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)); + +static Sys_var_ulong Sys_pfs_accounts_size( + "performance_schema_accounts_size", + "Maximum number of instrumented user@host accounts.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_account_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_MAX_ACCOUNT), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_hosts_size( + "performance_schema_hosts_size", + "Maximum number of instrumented hosts.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_host_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_MAX_HOST), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_users_size( + "performance_schema_users_size", + "Maximum number of instrumented users.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_user_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_MAX_USER), + 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)); + +static Sys_var_ulong Sys_pfs_events_stages_history_long_size( + "performance_schema_events_stages_history_long_size", + "Number of rows in EVENTS_STAGES_HISTORY_LONG.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_long_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_STAGES_HISTORY_LONG_SIZE), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_events_stages_history_size( + "performance_schema_events_stages_history_size", + "Number of rows per thread in EVENTS_STAGES_HISTORY.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024), + DEFAULT(PFS_STAGES_HISTORY_SIZE), + BLOCK_SIZE(1)); + +/** + Variable performance_schema_max_statement_classes. + The default number of statement classes is the sum of: + - COM_END 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. +*/ +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 + 3), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_events_statements_history_long_size( + "performance_schema_events_statements_history_long_size", + "Number of rows in EVENTS_STATEMENTS_HISTORY_LONG.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_long_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024), + DEFAULT(PFS_STATEMENTS_HISTORY_LONG_SIZE), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_events_statements_history_size( + "performance_schema_events_statements_history_size", + "Number of rows per thread in EVENTS_STATEMENTS_HISTORY.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024), + DEFAULT(PFS_STATEMENTS_HISTORY_SIZE), + BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_pfs_digest_size( + "performance_schema_digests_size", + "Size of the statement digest.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 200), + DEFAULT(PFS_DIGEST_SIZE), + BLOCK_SIZE(1)); + #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ static Sys_var_ulong Sys_auto_increment_increment( @@ -2209,6 +2333,19 @@ static Sys_var_charptr Sys_ssl_key( READ_ONLY GLOBAL_VAR(opt_ssl_key), SSL_OPT(OPT_SSL_KEY), IN_FS_CHARSET, DEFAULT(0)); +static Sys_var_charptr Sys_ssl_crl( + "ssl_crl", + "CRL file in PEM format (check OpenSSL docs, implies --ssl)", + READ_ONLY GLOBAL_VAR(opt_ssl_crl), SSL_OPT(OPT_SSL_CRL), + IN_FS_CHARSET, DEFAULT(0)); + +static Sys_var_charptr Sys_ssl_crlpath( + "ssl_crlpath", + "CRL directory (check OpenSSL docs, implies --ssl)", + READ_ONLY GLOBAL_VAR(opt_ssl_crlpath), SSL_OPT(OPT_SSL_CRLPATH), + IN_FS_CHARSET, DEFAULT(0)); + + // why ENUM and not BOOL ? static const char *updatable_views_with_limit_names[]= {"NO", "YES", 0}; static Sys_var_enum Sys_updatable_views_with_limit( @@ -2350,7 +2487,7 @@ static bool check_tx_isolation(sys_var *self, THD *thd, set_var *var) if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction()) { DBUG_ASSERT(thd->in_multi_stmt_transaction_mode()); - my_error(ER_CANT_CHANGE_TX_ISOLATION, MYF(0)); + my_error(ER_CANT_CHANGE_TX_CHARACTERISTICS, MYF(0)); return TRUE; } return FALSE; @@ -2363,6 +2500,42 @@ static Sys_var_tx_isolation Sys_tx_isolation( tx_isolation_names, DEFAULT(ISO_REPEATABLE_READ), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_isolation)); + +/** + Can't change the tx_read_only state if we are already in a + transaction. +*/ + +static bool check_tx_read_only(sys_var *self, THD *thd, set_var *var) +{ + if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction()) + { + DBUG_ASSERT(thd->in_multi_stmt_transaction_mode()); + my_error(ER_CANT_CHANGE_TX_CHARACTERISTICS, MYF(0)); + return true; + } + return false; +} + + +bool Sys_var_tx_read_only::session_update(THD *thd, set_var *var) +{ + if (var->type == OPT_SESSION && Sys_var_mybool::session_update(thd, var)) + return true; + if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction()) + { + // @see Sys_var_tx_isolation::session_update() above for the rules. + thd->tx_read_only= var->save_result.ulonglong_value; + } + return false; +} + + +static Sys_var_tx_read_only Sys_tx_read_only( + "tx_read_only", "Set default transaction access mode to read only.", + SESSION_VAR(tx_read_only), NO_CMD_LINE, DEFAULT(0), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_read_only)); + static Sys_var_ulonglong Sys_tmp_table_size( "tmp_table_size", "If an internal in-memory temporary table exceeds this size, MySQL " diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 1729dcefd63..ffa7de118c8 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -54,6 +54,7 @@ // this means that Sys_var_charptr initial value was malloc()ed #define PREALLOCATED sys_var::ALLOCATED+ #define PARSED_EARLY sys_var::PARSE_EARLY+ + /* Sys_var_bit meaning is reversed, like in @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS @@ -1930,6 +1931,30 @@ public: } }; + +/** + Class representing the tx_read_only system variable for setting + default transaction access mode. + + Note that there is a special syntax - SET TRANSACTION READ ONLY + (or READ WRITE) that sets the access mode for the next transaction + only. +*/ + +class Sys_var_tx_read_only: public Sys_var_mybool +{ +public: + Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args, + ptrdiff_t off, size_t size, CMD_LINE getopt, + my_bool def_val, PolyLock *lock, + enum binlog_status_enum binlog_status_arg, + on_check_function on_check_func) + :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt, + def_val, lock, binlog_status_arg, on_check_func) + {} + virtual bool session_update(THD *thd, set_var *var); +}; + /* Class for replicate_events_marked_for_skip. We need a custom update function that ensures the slave is stopped when diff --git a/sql/table.cc b/sql/table.cc index a011fa845a7..c8dc2b4ed5a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3636,9 +3636,9 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) } else if (MYSQL_VERSION_ID == table->s->mysql_version) { - report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, - ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), - table->alias.c_ptr(), + report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, + ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2), + table->s->db.str, table->s->table_name.str, table_def->count, table->s->fields); DBUG_RETURN(TRUE); } @@ -3884,7 +3884,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, mdl_context->find_deadlock(); wait_status= mdl_context->m_wait.timed_wait(thd, abstime, TRUE, - "Waiting for table flush"); + &stage_waiting_for_table_flush); mdl_context->done_waiting_for(); @@ -4064,7 +4064,8 @@ void TABLE::reset_item_list(List<Item> *item_list) const void TABLE_LIST::calc_md5(char *buffer) { uchar digest[16]; - MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length); + compute_md5_hash((char*) digest, select_stmt.str, + select_stmt.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc index da38d64fa4d..13deb167d9b 100644 --- a/sql/threadpool_unix.cc +++ b/sql/threadpool_unix.cc @@ -1345,7 +1345,7 @@ static int change_group(connection_t *c, thread_group_t *new_group) { int ret= 0; - int fd = c->thd->net.vio->sd; + int fd= mysql_socket_getfd(c->thd->net.vio->mysql_socket); DBUG_ASSERT(c->thread_group == old_group); @@ -1373,7 +1373,7 @@ static int change_group(connection_t *c, static int start_io(connection_t *connection) { - int fd = connection->thd->net.vio->sd; + int fd = mysql_socket_getfd(connection->thd->net.vio->mysql_socket); /* Usually, connection will stay in the same group for the entire diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc index 72e03da2453..9cef1af272c 100644 --- a/sql/threadpool_win.cc +++ b/sql/threadpool_win.cc @@ -255,7 +255,7 @@ int init_io(connection_t *connection, THD *thd) { case VIO_TYPE_SSL: case VIO_TYPE_TCPIP: - connection->handle= (HANDLE)vio->sd; + connection->handle= (HANDLE)mysql_socket_getfd(connection->thd->net.vio->mysql_socket); break; case VIO_TYPE_NAMEDPIPE: connection->handle= (HANDLE)vio->hPipe; @@ -342,7 +342,7 @@ int start_io(connection_t *connection, PTP_CALLBACK_INSTANCE instance) if (vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SSL) { /* Start async io (sockets). */ - if (WSARecv(vio->sd , &buf, 1, &num_bytes, &flags, + if (WSARecv(mysql_socket_getfd(vio->mysql_socket) , &buf, 1, &num_bytes, &flags, overlapped, NULL) == 0) { retval= last_error= 0; diff --git a/sql/transaction.cc b/sql/transaction.cc index 3359decbcd5..7d8fc89ec8c 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -22,6 +22,7 @@ #include "transaction.h" #include "rpl_handler.h" #include "debug_sync.h" // DEBUG_SYNC +#include "sql_acl.h" /* Conditions under which the transaction state must not change. */ static bool trans_check(THD *thd) @@ -134,7 +135,9 @@ bool trans_begin(THD *thd, uint flags) (thd->variables.option_bits & OPTION_TABLE_LOCK)) { thd->variables.option_bits&= ~OPTION_TABLE_LOCK; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= test(ha_commit_trans(thd, TRUE)); } @@ -150,9 +153,36 @@ bool trans_begin(THD *thd, uint flags) */ thd->mdl_context.release_transactional_locks(); + // The RO/RW options are mutually exclusive. + DBUG_ASSERT(!((flags & MYSQL_START_TRANS_OPT_READ_ONLY) && + (flags & MYSQL_START_TRANS_OPT_READ_WRITE))); + if (flags & MYSQL_START_TRANS_OPT_READ_ONLY) + thd->tx_read_only= true; + else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE) + { + /* + Explicitly starting a RW transaction when the server is in + read-only mode, is not allowed unless the user has SUPER priv. + Implicitly starting a RW transaction is allowed for backward + compatibility. + */ + const bool user_is_super= + test(thd->security_ctx->master_access & SUPER_ACL); + if (opt_readonly && !user_is_super) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + DBUG_RETURN(true); + } + thd->tx_read_only= false; + } + thd->variables.option_bits|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; + if (thd->tx_read_only) + thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY; + DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS")); + /* ha_start_consistent_snapshot() relies on OPTION_BEGIN flag set. */ if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) res= ha_start_consistent_snapshot(thd); @@ -177,16 +207,18 @@ bool trans_commit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_commit_trans(thd, TRUE); - if (res) /* if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. */ - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + if (res) + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); else - RUN_HOOK(transaction, after_commit, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_commit, (thd, FALSE)); thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; thd->lex->start_transaction_opt= 0; @@ -220,7 +252,9 @@ bool trans_commit_implicit(THD *thd) /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables_mode) thd->variables.option_bits&= ~OPTION_TABLE_LOCK; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= test(ha_commit_trans(thd, TRUE)); } @@ -229,11 +263,12 @@ bool trans_commit_implicit(THD *thd) /* Upon implicit commit, reset the current transaction - isolation level. We do not care about + isolation level and access mode. We do not care about @@session.completion_type since it's documented to not have any effect on implicit commit. */ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; DBUG_RETURN(res); } @@ -256,9 +291,11 @@ bool trans_rollback(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); res= ha_rollback_trans(thd, TRUE); - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; thd->lex->start_transaction_opt= 0; @@ -298,17 +335,20 @@ bool trans_commit_stmt(THD *thd) { res= ha_commit_trans(thd, FALSE); if (! thd->in_active_multi_stmt_transaction()) + { thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; + } } - if (res) /* if res is non-zero, then ha_commit_trans has rolled back the transaction, so the hooks for rollback will be called. */ - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + if (res) + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); else - RUN_HOOK(transaction, after_commit, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_commit, (thd, FALSE)); thd->transaction.stmt.reset(); @@ -342,10 +382,13 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction_rollback_request && !thd->in_sub_stmt) ha_rollback_trans(thd, TRUE); if (! thd->in_active_multi_stmt_transaction()) + { thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; + thd->tx_read_only= thd->variables.tx_read_only; + } } - RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); thd->transaction.stmt.reset(); @@ -722,7 +765,9 @@ bool trans_xa_commit(THD *thd) thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state= XA_NOTR; @@ -769,7 +814,9 @@ bool trans_xa_rollback(THD *thd) thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; - thd->server_status&= ~SERVER_STATUS_IN_TRANS; + thd->server_status&= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state= XA_NOTR; diff --git a/sql/unireg.cc b/sql/unireg.cc index 20d101be1a3..e40dc02c21b 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -241,8 +241,7 @@ bool mysql_create_frm(THD *thd, const char *file_name, (real_table_name= field->field->table->s->table_name.str)) break; } - if ((thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + if (thd->is_strict_mode()) { my_error(ER_TOO_LONG_TABLE_COMMENT, MYF(0), real_table_name, static_cast<ulong>(TABLE_COMMENT_MAXLEN)); @@ -707,8 +706,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type, COLUMN_COMMENT_MAXLEN); if (tmp_len < field->comment.length) { - if ((current_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + if (current_thd->is_strict_mode()) { my_error(ER_TOO_LONG_FIELD_COMMENT, MYF(0), field->field_name, static_cast<ulong>(COLUMN_COMMENT_MAXLEN)); |