summaryrefslogtreecommitdiff
path: root/sql/sql_class.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r--sql/sql_class.h1368
1 files changed, 1019 insertions, 349 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2fac8d4e87f..9805b618d89 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -15,26 +15,19 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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
-#endif
#include <waiting_threads.h>
#include "sql_const.h"
#include <mysql/plugin_audit.h>
#include "log.h"
#include "rpl_tblmap.h"
#include "mdl.h"
+#include "field.h" // Create_field
#include "probes_mysql.h"
#include "sql_locale.h" /* my_locale_st */
#include "sql_profile.h" /* PROFILING */
@@ -43,10 +36,32 @@
#include "violite.h" /* vio_is_connected */
#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
THR_LOCK_INFO */
-
+#include "sql_digest_stream.h" // sql_digest_state
+
+#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"
+#include "rpl_gtid.h"
class Reprepare_observer;
class Relay_log_info;
+struct rpl_group_info;
+class Rpl_filter;
class Query_log_event;
class Load_log_event;
class Slave_log_event;
@@ -56,18 +71,21 @@ class Lex_input_stream;
class Parser_state;
class Rows_log_event;
class Sroutine_hash_entry;
-class User_level_lock;
class user_var_entry;
struct Trans_binlog_info;
+class rpl_io_thread_info;
+class rpl_sql_thread_info;
-enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
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_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO,
+ SLAVE_RUN_TRIGGERS_FOR_RBR_YES,
+ SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING};
enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
enum enum_mark_columns
@@ -75,45 +93,47 @@ enum enum_mark_columns
enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
/* Bits for different SQL modes modes (including ANSI mode) */
-#define MODE_REAL_AS_FLOAT 1
-#define MODE_PIPES_AS_CONCAT 2
-#define MODE_ANSI_QUOTES 4
-#define MODE_IGNORE_SPACE 8
-#define MODE_IGNORE_BAD_TABLE_OPTIONS 16
-#define MODE_ONLY_FULL_GROUP_BY 32
-#define MODE_NO_UNSIGNED_SUBTRACTION 64
-#define MODE_NO_DIR_IN_CREATE 128
-#define MODE_POSTGRESQL 256
-#define MODE_ORACLE 512
-#define MODE_MSSQL 1024
-#define MODE_DB2 2048
-#define MODE_MAXDB 4096
-#define MODE_NO_KEY_OPTIONS 8192
-#define MODE_NO_TABLE_OPTIONS 16384
-#define MODE_NO_FIELD_OPTIONS 32768
-#define MODE_MYSQL323 65536L
-#define MODE_MYSQL40 (MODE_MYSQL323*2)
-#define MODE_ANSI (MODE_MYSQL40*2)
-#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
-#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
-#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
-#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
-#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
-#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
-#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
-#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
-#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
-#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
-#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
-#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
-#define MODE_PAD_CHAR_TO_FULL_LENGTH (ULL(1) << 31)
+#define MODE_REAL_AS_FLOAT (1ULL << 0)
+#define MODE_PIPES_AS_CONCAT (1ULL << 1)
+#define MODE_ANSI_QUOTES (1ULL << 2)
+#define MODE_IGNORE_SPACE (1ULL << 3)
+#define MODE_IGNORE_BAD_TABLE_OPTIONS (1ULL << 4)
+#define MODE_ONLY_FULL_GROUP_BY (1ULL << 5)
+#define MODE_NO_UNSIGNED_SUBTRACTION (1ULL << 6)
+#define MODE_NO_DIR_IN_CREATE (1ULL << 7)
+#define MODE_POSTGRESQL (1ULL << 8)
+#define MODE_ORACLE (1ULL << 9)
+#define MODE_MSSQL (1ULL << 10)
+#define MODE_DB2 (1ULL << 11)
+#define MODE_MAXDB (1ULL << 12)
+#define MODE_NO_KEY_OPTIONS (1ULL << 13)
+#define MODE_NO_TABLE_OPTIONS (1ULL << 14)
+#define MODE_NO_FIELD_OPTIONS (1ULL << 15)
+#define MODE_MYSQL323 (1ULL << 16)
+#define MODE_MYSQL40 (1ULL << 17)
+#define MODE_ANSI (1ULL << 18)
+#define MODE_NO_AUTO_VALUE_ON_ZERO (1ULL << 19)
+#define MODE_NO_BACKSLASH_ESCAPES (1ULL << 20)
+#define MODE_STRICT_TRANS_TABLES (1ULL << 21)
+#define MODE_STRICT_ALL_TABLES (1ULL << 22)
+#define MODE_NO_ZERO_IN_DATE (1ULL << 23)
+#define MODE_NO_ZERO_DATE (1ULL << 24)
+#define MODE_INVALID_DATES (1ULL << 25)
+#define MODE_ERROR_FOR_DIVISION_BY_ZERO (1ULL << 26)
+#define MODE_TRADITIONAL (1ULL << 27)
+#define MODE_NO_AUTO_CREATE_USER (1ULL << 28)
+#define MODE_HIGH_NOT_PRECEDENCE (1ULL << 29)
+#define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30)
+#define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31)
/* Bits for different old style modes */
-#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE 1
-#define OLD_MODE_NO_PROGRESS_INFO 2
+#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0)
+#define OLD_MODE_NO_PROGRESS_INFO (1 << 1)
+#define OLD_MODE_ZERO_DATE_TIME_CAST (1 << 2)
extern char internal_table_name[2];
extern char empty_c_string[1];
+extern LEX_STRING EMPTY_STR;
extern MYSQL_PLUGIN_IMPORT const char **errmesg;
extern bool volatile shutdown_in_progress;
@@ -153,9 +173,6 @@ public:
};
-#define TC_LOG_PAGE_SIZE 8192
-#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
-
#define TC_HEURISTIC_RECOVER_COMMIT 1
#define TC_HEURISTIC_RECOVER_ROLLBACK 2
extern ulong tc_heuristic_recover;
@@ -227,11 +244,15 @@ public:
class Alter_drop :public Sql_alloc {
public:
- enum drop_type {KEY, COLUMN };
+ enum drop_type {KEY, COLUMN, FOREIGN_KEY };
const char *name;
enum drop_type type;
- Alter_drop(enum drop_type par_type,const char *par_name)
- :name(par_name), type(par_type) {}
+ bool drop_if_exists;
+ Alter_drop(enum drop_type par_type,const char *par_name, bool par_exists)
+ :name(par_name), type(par_type), drop_if_exists(par_exists)
+ {
+ DBUG_ASSERT(par_name != NULL);
+ }
/**
Used to make a clone of this object for ALTER/CREATE TABLE
@sa comment for Key_part_spec::clone
@@ -265,20 +286,23 @@ public:
LEX_STRING name;
engine_option_value *option_list;
bool generated;
+ bool create_if_not_exists;
Key(enum Keytype type_par, const LEX_STRING &name_arg,
KEY_CREATE_INFO *key_info_arg,
bool generated_arg, List<Key_part_spec> &cols,
- engine_option_value *create_opt)
+ engine_option_value *create_opt, bool if_not_exists_opt)
:type(type_par), key_create_info(*key_info_arg), columns(cols),
- name(name_arg), option_list(create_opt), generated(generated_arg)
+ name(name_arg), option_list(create_opt), generated(generated_arg),
+ create_if_not_exists(if_not_exists_opt)
{}
Key(enum Keytype type_par, const char *name_arg, size_t name_len_arg,
KEY_CREATE_INFO *key_info_arg, bool generated_arg,
List<Key_part_spec> &cols,
- engine_option_value *create_opt)
+ engine_option_value *create_opt, bool if_not_exists_opt)
:type(type_par), key_create_info(*key_info_arg), columns(cols),
- option_list(create_opt), generated(generated_arg)
+ option_list(create_opt), generated(generated_arg),
+ create_if_not_exists(if_not_exists_opt)
{
name.str= (char *)name_arg;
name.length= name_len_arg;
@@ -295,27 +319,31 @@ public:
{ return new (mem_root) Key(*this, mem_root); }
};
-class Table_ident;
class Foreign_key: public Key {
public:
enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
- enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
- FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
- Table_ident *ref_table;
+ LEX_STRING ref_db;
+ LEX_STRING ref_table;
List<Key_part_spec> ref_columns;
uint delete_opt, update_opt, match_opt;
Foreign_key(const LEX_STRING &name_arg, List<Key_part_spec> &cols,
- Table_ident *table, List<Key_part_spec> &ref_cols,
- uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
- :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL),
- ref_table(table), ref_columns(ref_cols),
+ const LEX_STRING &ref_db_arg, const LEX_STRING &ref_table_arg,
+ List<Key_part_spec> &ref_cols,
+ uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg,
+ bool if_not_exists_opt)
+ :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL,
+ if_not_exists_opt),
+ ref_db(ref_db_arg), ref_table(ref_table_arg), ref_columns(ref_cols),
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
- {}
- Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root);
+ {
+ // We don't check for duplicate FKs.
+ key_create_info.check_for_duplicate_indexes= false;
+ }
+ Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root);
/**
Used to make a clone of this object for ALTER/CREATE TABLE
@sa comment for Key_part_spec::clone
@@ -438,7 +466,8 @@ extern int killed_errno(killed_state killed);
enum killed_type
{
KILL_TYPE_ID,
- KILL_TYPE_USER
+ KILL_TYPE_USER,
+ KILL_TYPE_QUERY
};
#include "sql_lex.h" /* Must be here */
@@ -453,6 +482,8 @@ class Time_zone;
#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
+typedef ulonglong sql_mode_t;
+
typedef struct system_variables
{
/*
@@ -476,8 +507,8 @@ typedef struct system_variables
ulonglong tmp_table_size;
ulonglong long_query_time;
ulonglong optimizer_switch;
- ulonglong sql_mode; ///< which non-standard SQL behaviour should be enabled
- ulonglong old_behavior; ///< which old SQL behaviour should be enabled
+ sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled
+ sql_mode_t old_behavior; ///< which old SQL behaviour should be enabled
ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
ulonglong join_buff_space_limit;
ulonglong log_slow_filter;
@@ -486,6 +517,15 @@ typedef struct system_variables
ulonglong join_buff_size;
ulonglong sortbuff_size;
ulonglong group_concat_max_len;
+ ulonglong default_regex_flags;
+
+ /**
+ Place holders to store Multi-source variables in sys_var.cc during
+ update and show of variables.
+ */
+ ulonglong slave_skip_counter;
+ ulonglong max_relay_log_size;
+
ha_rows select_limit;
ha_rows max_join_size;
ha_rows expensive_subquery_limit;
@@ -508,6 +548,11 @@ typedef struct system_variables
ulong net_write_timeout;
ulong optimizer_prune_level;
ulong optimizer_search_depth;
+ ulong optimizer_selectivity_sampling_limit;
+ ulong optimizer_use_condition_selectivity;
+ ulong use_stat_tables;
+ ulong histogram_size;
+ ulong histogram_type;
ulong preload_buff_size;
ulong profiling_history_size;
ulong read_buff_size;
@@ -537,12 +582,23 @@ typedef struct system_variables
ulong tx_isolation;
ulong updatable_views_with_limit;
int max_user_connections;
+ ulong server_id;
/**
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
*/
my_thread_id pseudo_thread_id;
+ /**
+ When replicating an event group with GTID, keep these values around so
+ slave binlog can receive the same GTID as the original.
+ */
+ uint32 gtid_domain_id;
+ uint64 gtid_seq_no;
+ /**
+ 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;
@@ -566,6 +622,9 @@ typedef struct system_variables
CHARSET_INFO *collation_database;
CHARSET_INFO *collation_connection;
+ /* Names. These will be allocated in buffers in thd */
+ LEX_STRING default_master_connection;
+
/* Error messages */
MY_LOCALE *lc_messages;
/* Locale Support */
@@ -595,8 +654,9 @@ typedef struct system_status_var
{
ulong com_other;
ulong com_stat[(uint) SQLCOM_END];
- ulong created_tmp_disk_tables;
- ulong created_tmp_tables;
+ ulong com_register_slave;
+ ulong created_tmp_disk_tables_;
+ ulong created_tmp_tables_;
ulong ha_commit_count;
ulong ha_delete_count;
ulong ha_read_first_count;
@@ -604,9 +664,11 @@ typedef struct system_status_var
ulong ha_read_key_count;
ulong ha_read_next_count;
ulong ha_read_prev_count;
+ ulong ha_read_retry_count;
ulong ha_read_rnd_count;
ulong ha_read_rnd_next_count;
ulong ha_read_rnd_deleted_count;
+
/*
This number doesn't include calls to the default implementation and
calls made by range access. The intent is to count only calls made by
@@ -628,23 +690,27 @@ 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 update_scan_count;
+ ulong delete_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_;
+ ulong filesort_pq_sorts_;
/* Prepared statements and binary protocol */
ulong com_stmt_prepare;
ulong com_stmt_reprepare;
@@ -685,6 +751,8 @@ typedef struct system_status_var
ulonglong binlog_bytes_written;
double last_query_cost;
double cpu_time, busy_time;
+ /* Don't initialize */
+ volatile int64 memory_used; /* This shouldn't be accumulated */
} STATUS_VAR;
/*
@@ -694,12 +762,47 @@ typedef struct system_status_var
*/
#define last_system_status_var questions
+#define last_cleared_system_status_var memory_used
+
+/*
+ Global status variables
+*/
+
+extern ulong feature_files_opened_with_delayed_keys;
+
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
STATUS_VAR *dec_var);
+/**
+ Get collation by name, send error to client on failure.
+ @param name Collation name
+ @param name_cs Character set of the name string
+ @return
+ @retval NULL on error
+ @retval Pointter to CHARSET_INFO with the given name on success
+*/
+inline CHARSET_INFO *
+mysqld_collation_get_by_name(const char *name,
+ CHARSET_INFO *name_cs= system_charset_info)
+{
+ CHARSET_INFO *cs;
+ MY_CHARSET_LOADER loader;
+ my_charset_loader_init_mysys(&loader);
+ if (!(cs= my_collation_get_by_name(&loader, name, MYF(0))))
+ {
+ ErrConvString err(name, name_cs);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), err.ptr());
+ if (loader.error[0])
+ push_warning_printf(current_thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_COLLATION, "%s", loader.error);
+ }
+ return cs;
+}
+
#ifdef MYSQL_SERVER
void free_tmp_table(THD *thd, TABLE *entry);
@@ -1046,6 +1149,8 @@ public:
char proxy_user[USERNAME_LENGTH + MAX_HOSTNAME + 5];
/* The host privilege we are using */
char priv_host[MAX_HOSTNAME];
+ /* The role privilege we are using */
+ char priv_role[USERNAME_LENGTH];
/* The external user (if available) */
char *external_user;
/* points to host if host is available, otherwise points to ip */
@@ -1286,7 +1391,9 @@ enum enum_thread_type
SYSTEM_THREAD_SLAVE_SQL= 4,
SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
SYSTEM_THREAD_EVENT_SCHEDULER= 16,
- SYSTEM_THREAD_EVENT_WORKER= 32
+ SYSTEM_THREAD_EVENT_WORKER= 32,
+ SYSTEM_THREAD_BINLOG_BACKGROUND= 64,
+ SYSTEM_THREAD_SLAVE_INIT= 128,
};
inline char const *
@@ -1351,9 +1458,9 @@ public:
virtual bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl) = 0;
+ Sql_condition ** cond_hdl) = 0;
private:
Internal_error_handler *m_prev_internal_handler;
@@ -1372,9 +1479,9 @@ public:
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl)
+ Sql_condition ** cond_hdl)
{
/* Ignore error */
return TRUE;
@@ -1384,6 +1491,29 @@ public:
/**
+ Implements the trivial error handler which counts errors as they happen.
+*/
+
+class Counting_error_handler : public Internal_error_handler
+{
+public:
+ int errors;
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ Sql_condition::enum_warning_level level,
+ const char* msg,
+ Sql_condition ** cond_hdl)
+ {
+ if (level == Sql_condition::WARN_LEVEL_ERROR)
+ errors++;
+ return false;
+ }
+ Counting_error_handler() : errors(0) {}
+};
+
+
+/**
This class is an internal error handler implementation for
DROP TABLE statements. The thing is that there may be warnings during
execution of these statements, which should not be exposed to the user.
@@ -1399,9 +1529,9 @@ public:
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl);
+ Sql_condition ** cond_hdl);
private:
};
@@ -1454,13 +1584,16 @@ public:
m_reopen_array(NULL),
m_locked_tables_count(0)
{
- init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0);
+ init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
}
void unlock_locked_tables(THD *thd);
+ void unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket);
~Locked_tables_list()
{
- unlock_locked_tables(0);
+ reset();
}
+ void reset();
bool init_locked_tables(THD *thd);
TABLE_LIST *locked_tables() { return m_locked_tables; }
void unlink_from_list(THD *thd, TABLE_LIST *table_list,
@@ -1468,7 +1601,10 @@ public:
void unlink_all_closed_tables(THD *thd,
MYSQL_LOCK *lock,
size_t reopen_count);
- bool reopen_tables(THD *thd);
+ bool reopen_tables(THD *thd, bool need_reopen);
+ bool restore_lock(THD *thd, TABLE_LIST *dst_table_list, TABLE *table,
+ MYSQL_LOCK *lock);
+ void add_back_last_deleted_lock(TABLE_LIST *dst_table_list);
};
@@ -1558,8 +1694,163 @@ private:
};
+/*
+ Class to facilitate the commit of one transactions waiting for the commit of
+ another transaction to complete first.
+
+ This is used during (parallel) replication, to allow different transactions
+ to be applied in parallel, but still commit in order.
+
+ The transaction that wants to wait for a prior commit must first register
+ to wait with register_wait_for_prior_commit(waitee). Such registration
+ must be done holding the waitee->LOCK_wait_commit, to prevent the other
+ THD from disappearing during the registration.
+
+ Then during commit, if a THD is registered to wait, it will call
+ wait_for_prior_commit() as part of ha_commit_trans(). If no wait is
+ registered, or if the waitee for has already completed commit, then
+ wait_for_prior_commit() returns immediately.
+
+ And when a THD that may be waited for has completed commit (more precisely
+ commit_ordered()), then it must call wakeup_subsequent_commits() to wake
+ up any waiters. Note that this must be done at a point that is guaranteed
+ to be later than any waiters registering themselves. It is safe to call
+ wakeup_subsequent_commits() multiple times, as waiters are removed from
+ registration as part of the wakeup.
+
+ The reason for separate register and wait calls is that this allows to
+ register the wait early, at a point where the waited-for THD is known to
+ exist. And then the actual wait can be done much later, where the
+ waited-for THD may have been long gone. By registering early, the waitee
+ can signal before disappearing.
+*/
+struct wait_for_commit
+{
+ /*
+ The LOCK_wait_commit protects the fields subsequent_commits_list and
+ wakeup_subsequent_commits_running (for a waitee), and the pointer
+ waiterr and associated COND_wait_commit (for a waiter).
+ */
+ mysql_mutex_t LOCK_wait_commit;
+ mysql_cond_t COND_wait_commit;
+ /* List of threads that did register_wait_for_prior_commit() on us. */
+ wait_for_commit *subsequent_commits_list;
+ /* Link field for entries in subsequent_commits_list. */
+ wait_for_commit *next_subsequent_commit;
+ /*
+ Our waitee, if we did register_wait_for_prior_commit(), and were not
+ yet woken up. Else NULL.
+
+ When this is cleared for wakeup, the COND_wait_commit condition is
+ signalled.
+ */
+ wait_for_commit *waitee;
+ /*
+ Generic pointer for use by the transaction coordinator to optimise the
+ waiting for improved group commit.
+
+ Currently used by binlog TC to signal that a waiter is ready to commit, so
+ that the waitee can grab it and group commit it directly. It is free to be
+ used by another transaction coordinator for similar purposes.
+ */
+ void *opaque_pointer;
+ /* The wakeup error code from the waitee. 0 means no error. */
+ int wakeup_error;
+ /*
+ Flag set when wakeup_subsequent_commits_running() is active, see comments
+ on that function for details.
+ */
+ bool wakeup_subsequent_commits_running;
+ /*
+ This flag can be set when a commit starts, but has not completed yet.
+ It is used by binlog group commit to allow a waiting transaction T2 to
+ join the group commit of an earlier transaction T1. When T1 has queued
+ itself for group commit, it will set the commit_started flag. Then when
+ T2 becomes ready to commit and needs to wait for T1 to commit first, T2
+ can queue itself before waiting, and thereby participate in the same
+ group commit as T1.
+ */
+ bool commit_started;
+
+ void register_wait_for_prior_commit(wait_for_commit *waitee);
+ int wait_for_prior_commit(THD *thd)
+ {
+ /*
+ Quick inline check, to avoid function call and locking in the common case
+ where no wakeup is registered, or a registered wait was already signalled.
+ */
+ if (waitee)
+ return wait_for_prior_commit2(thd);
+ else
+ {
+ if (wakeup_error)
+ my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
+ return wakeup_error;
+ }
+ }
+ void wakeup_subsequent_commits(int wakeup_error)
+ {
+ /*
+ Do the check inline, so only the wakeup case takes the cost of a function
+ call for every commmit.
+
+ Note that the check is done without locking. It is the responsibility of
+ the user of the wakeup facility to ensure that no waiters can register
+ themselves after the last call to wakeup_subsequent_commits().
+
+ This avoids having to take another lock for every commit, which would be
+ pointless anyway - even if we check under lock, there is nothing to
+ prevent a waiter from arriving just after releasing the lock.
+ */
+ if (subsequent_commits_list)
+ wakeup_subsequent_commits2(wakeup_error);
+ }
+ void unregister_wait_for_prior_commit()
+ {
+ if (waitee)
+ unregister_wait_for_prior_commit2();
+ else
+ wakeup_error= 0;
+ }
+ /*
+ Remove a waiter from the list in the waitee. Used to unregister a wait.
+ The caller must be holding the locks of both waiter and waitee.
+ */
+ void remove_from_list(wait_for_commit **next_ptr_ptr)
+ {
+ wait_for_commit *cur;
+
+ while ((cur= *next_ptr_ptr) != NULL)
+ {
+ if (cur == this)
+ {
+ *next_ptr_ptr= this->next_subsequent_commit;
+ break;
+ }
+ next_ptr_ptr= &cur->next_subsequent_commit;
+ }
+ waitee= NULL;
+ }
+
+ void wakeup(int wakeup_error);
+
+ int wait_for_prior_commit2(THD *thd);
+ void wakeup_subsequent_commits2(int wakeup_error);
+ void unregister_wait_for_prior_commit2();
+
+ wait_for_commit();
+ ~wait_for_commit();
+ void reinit();
+};
+
+
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
+class THD;
+#ifndef DBUG_OFF
+void dbug_serve_apcs(THD *thd, int n_calls);
+#endif
+
/**
@class THD
For each client connection we create a separate thread with THD serving as
@@ -1567,6 +1858,7 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
*/
class THD :public Statement,
+ public MDL_context_owner,
public Open_tables_state
{
private:
@@ -1587,8 +1879,14 @@ public:
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
+ rpl_group_info* rgi_fake;
/* Slave applier execution context */
- Relay_log_info* rli_slave;
+ rpl_group_info* rgi_slave;
+
+ union {
+ rpl_io_thread_info *rpl_io_info;
+ rpl_sql_thread_info *rpl_sql_info;
+ } system_thread_info;
void reset_for_next_command();
/*
@@ -1622,6 +1920,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
@@ -1688,6 +1988,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
@@ -1703,21 +2016,23 @@ public:
HASH handler_tables_hash;
/*
- One thread can hold up to one named user-level lock. This variable
- points to a lock object if the lock is present. See item_func.cc and
+ A thread can hold named user-level locks. This variable
+ contains granted tickets if a lock is present. See item_func.cc and
chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
- User_level_lock *ull;
+ HASH ull_hash;
#ifndef DBUG_OFF
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;
- uint32 server_id;
+ enum enum_server_command m_command;
+
+public:
uint32 file_id; // for LOAD DATA INFILE
/* remote (peer) port */
uint16 peer_port;
@@ -1755,7 +2070,10 @@ public:
uint in_sub_stmt;
/* True when opt_userstat_running is set at start of query */
bool userstat_running;
- /* True if we want to log all errors */
+ /*
+ True if we have to log all errors. Are set by some engines to temporary
+ force errors to the error log.
+ */
bool log_all_errors;
/* Do not set socket timeouts for wait_timeout (used with threadpool) */
@@ -1797,7 +2115,7 @@ public:
MY_BITMAP const* cols, size_t colcnt,
const uchar *old_data, const uchar *new_data);
- void set_server_id(uint32 sid) { server_id = sid; }
+ void set_server_id(uint32 sid) { variables.server_id = sid; }
/*
Member functions to handle pending event for row-level logging.
@@ -1845,8 +2163,46 @@ public:
!mysql_bin_log.is_open());
}
+ enum binlog_filter_state
+ {
+ BINLOG_FILTER_UNKNOWN,
+ BINLOG_FILTER_CLEAR,
+ BINLOG_FILTER_SET
+ };
+
+ inline void reset_binlog_local_stmt_filter()
+ {
+ m_binlog_filter_state= BINLOG_FILTER_UNKNOWN;
+ }
+
+ inline void clear_binlog_local_stmt_filter()
+ {
+ DBUG_ASSERT(m_binlog_filter_state == BINLOG_FILTER_UNKNOWN);
+ m_binlog_filter_state= BINLOG_FILTER_CLEAR;
+ }
+
+ inline void set_binlog_local_stmt_filter()
+ {
+ DBUG_ASSERT(m_binlog_filter_state == BINLOG_FILTER_UNKNOWN);
+ m_binlog_filter_state= BINLOG_FILTER_SET;
+ }
+
+ inline binlog_filter_state get_binlog_local_stmt_filter()
+ {
+ return m_binlog_filter_state;
+ }
+
private:
/**
+ Indicate if the current statement should be discarded
+ instead of written to the binlog.
+ This is used to discard special statements, such as
+ DML or DDL that affects only 'local' (non replicated)
+ tables, such as performance_schema.*
+ */
+ binlog_filter_state m_binlog_filter_state;
+
+ /**
Indicates the format in which the current statement will be
logged. This can only be set from @c decide_logging_format().
*/
@@ -1924,7 +2280,8 @@ public:
{
bzero((char*)this, sizeof(*this));
xid_state.xid.null();
- init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
}
} transaction;
Global_read_lock global_read_lock;
@@ -2148,11 +2505,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
@@ -2164,12 +2522,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.
@@ -2182,12 +2570,30 @@ public:
USER_CONN *user_connect;
CHARSET_INFO *db_charset;
- Warning_info *warning_info;
- Diagnostics_area *stmt_da;
#if defined(ENABLED_PROFILING)
PROFILING profiling;
#endif
+ /** Current statement digest. */
+ sql_digest_state *m_digest;
+ /** Current statement digest token array. */
+ unsigned char *m_token_array;
+ /** Top level statement digest. */
+ sql_digest_state m_digest_state;
+
+ /** 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 */
+
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
@@ -2235,12 +2641,23 @@ 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 */
MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */
/*
+ Define durability properties that engines may check to
+ improve performance. Not yet used in MariaDB
+ */
+ enum durability_properties durability_property;
+
+ /*
If checking this in conjunction with a wait condition, please
include a check after enter_cond() if you want to avoid a race
condition. For details see the implementation of awake(),
@@ -2248,15 +2665,31 @@ public:
*/
killed_state volatile killed;
+ /* See also thd_killed() */
+ inline bool check_killed()
+ {
+ if (killed)
+ return TRUE;
+ if (apc_target.have_apc_requests())
+ apc_target.process_apc_requests();
+ return FALSE;
+ }
+
/* scramble - random string sent to client on handshake */
char scramble[SCRAMBLE_LENGTH+1];
- bool slave_thread, one_shot_set;
+ /*
+ If this is a slave, the name of the connection stored here.
+ This is used for taging error messages in the log files.
+ */
+ LEX_STRING connection_name;
+ char default_master_connection_buff[MAX_CONNECTION_NAME+1];
+ uint8 password; /* 0, 1 or 2 */
+ uint8 failed_com_change_user;
+ bool slave_thread;
bool extra_port; /* If extra connection */
bool no_errors;
- uint8 password;
- uint8 failed_com_change_user;
/**
Set to TRUE if execution of the current compound statement
@@ -2289,13 +2722,6 @@ public:
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
bool substitute_null_with_insert_id;
bool in_lock_tables;
- /**
- True if a slave error. Causes the slave to stop. Not the same
- as the statement execution error (is_error()), since
- a statement may be expected to return an error, e.g. because
- it returned an error on master, and this is OK on the slave.
- */
- bool is_slave_error;
bool bootstrap, cleanup_done;
/** is set if some thread specific value(s) used in a statement. */
@@ -2312,6 +2738,32 @@ public:
/* set during loop of derived table processing */
bool derived_tables_processing;
bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
+ /* True if we have to log the current statement */
+ bool log_current_statement;
+ /**
+ True if a slave error. Causes the slave to stop. Not the same
+ as the statement execution error (is_error()), since
+ a statement may be expected to return an error, e.g. because
+ it returned an error on master, and this is OK on the slave.
+ */
+ bool is_slave_error;
+ /*
+ True when a transaction is queued up for binlog group commit.
+ Used so that if another transaction needs to wait for a row lock held by
+ this transaction, it can signal to trigger the group commit immediately,
+ skipping the normal --binlog-commit-wait-count wait.
+ */
+ bool waiting_on_group_commit;
+ /*
+ Set true when another transaction goes to wait on a row lock held by this
+ transaction. Used together with waiting_on_group_commit.
+ */
+ bool has_waiter;
+ /*
+ In case of a slave, set to the error code the master got when executing
+ the query. 0 if no error on the master.
+ */
+ int slave_expected_error;
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
@@ -2447,10 +2899,21 @@ public:
void close_active_vio();
#endif
void awake(killed_state state_to_set);
-
+
/** Disconnect the associated communication endpoint. */
void disconnect();
+
+ /*
+ Allows this thread to serve as a target for others to schedule Async
+ Procedure Calls on.
+
+ It's possible to schedule any code to be executed this way, by
+ inheriting from the Apc_call object. Currently, only
+ Show_explain_request uses this.
+ */
+ Apc_target apc_target;
+
#ifndef MYSQL_CLIENT
enum enum_binlog_query_type {
/* The query can be logged in row format or in statement format. */
@@ -2468,22 +2931,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
@@ -2495,10 +2956,51 @@ 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;
}
+ virtual int is_killed() { return killed; }
+ virtual THD* get_thd() { return this; }
+
+ /**
+ A callback to the server internals that is used to address
+ special cases of the locking protocol.
+ Invoked when acquiring an exclusive lock, for each thread that
+ has a conflicting shared metadata lock.
+
+ This function:
+ - aborts waiting of the thread on a data lock, to make it notice
+ the pending exclusive lock and back off.
+ - if the thread is an INSERT DELAYED thread, sends it a KILL
+ signal to terminate it.
+
+ @note This function does not wait for the thread to give away its
+ locks. Waiting is done outside for all threads at once.
+
+ @param ctx_in_use The MDL context owner (thread) to wake up.
+ @param needs_thr_lock_abort Indicates that to wake up thread
+ this call needs to abort its waiting
+ on table-level lock.
+
+ @retval TRUE if the thread was woken up
+ @retval FALSE otherwise.
+ */
+ virtual bool notify_shared_lock(MDL_context_owner *ctx_in_use,
+ bool needs_thr_lock_abort);
+
+ // End implementation of MDL_context_owner interface.
+
+ inline bool use_cond_push(handler *file)
+ {
+ return (variables.optimizer_switch & OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN)
+ || (file->ha_table_flags() & HA_MUST_USE_TABLE_CONDITION_PUSHDOWN);
+ }
+ inline bool is_strict_mode() const
+ {
+ return (bool) (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; }
@@ -2507,6 +3009,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_THREAD_CALL(set_thread_start_time)(start_time);
+#endif
}
inline void set_start_time()
{
@@ -2514,6 +3019,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_THREAD_CALL(set_thread_start_time)(start_time);
+#endif
}
else
set_current_time();
@@ -2523,17 +3031,22 @@ public:
set_start_time();
start_utime= utime_after_lock= microsecond_interval_timer();
}
- inline void set_time(my_hrtime_t t)
+ inline void set_time(my_hrtime_t t)
{
user_time= t;
set_time();
}
- inline void set_time(my_time_t t, ulong sec_part)
+ inline void set_time(my_time_t t, ulong sec_part)
{
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(); }
/**
@@ -2630,9 +3143,21 @@ public:
return alloc_root(&transaction.mem_root,size);
}
- LEX_STRING *make_lex_string(LEX_STRING *lex_str,
- const char* str, uint length,
- bool allocate_lex_string);
+ LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, uint length)
+ {
+ if (!(lex_str->str= strmake_root(mem_root, str, length)))
+ return 0;
+ lex_str->length= length;
+ return lex_str;
+ }
+
+ LEX_STRING *make_lex_string(const char* str, uint length)
+ {
+ LEX_STRING *lex_str;
+ if (!(lex_str= (LEX_STRING *)alloc_root(mem_root, sizeof(LEX_STRING))))
+ return 0;
+ return make_lex_string(lex_str, str, length);
+ }
bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
const char *from, uint from_length,
@@ -2644,7 +3169,7 @@ public:
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
int send_explain_fields(select_result *result);
-
+ void make_explain_field_list(List<Item> &field_list);
/**
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
@@ -2658,8 +3183,8 @@ public:
inline void clear_error()
{
DBUG_ENTER("clear_error");
- if (stmt_da->is_error())
- stmt_da->reset_diagnostics_area();
+ if (get_stmt_da()->is_error())
+ get_stmt_da()->reset_diagnostics_area();
is_slave_error= 0;
if (killed == KILL_BAD_DATA)
killed= NOT_KILLED; // KILL_BAD_DATA can be reset w/o a mutex
@@ -2688,7 +3213,7 @@ public:
*/
inline void fatal_error()
{
- DBUG_ASSERT(stmt_da->is_error() || killed);
+ DBUG_ASSERT(get_stmt_da()->is_error() || killed);
is_fatal_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
@@ -2705,7 +3230,20 @@ public:
To raise this flag, use my_error().
*/
- inline bool is_error() const { return stmt_da->is_error(); }
+ inline bool is_error() const { return m_stmt_da->is_error(); }
+
+ /// Returns Diagnostics-area for the current statement.
+ Diagnostics_area *get_stmt_da()
+ { return m_stmt_da; }
+
+ /// Returns Diagnostics-area for the current statement.
+ const Diagnostics_area *get_stmt_da() const
+ { return m_stmt_da; }
+
+ /// Sets Diagnostics-area for the current statement.
+ void set_stmt_da(Diagnostics_area *da)
+ { m_stmt_da= da; }
+
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
@@ -2782,6 +3320,14 @@ public:
mysql_mutex_unlock(&LOCK_thd_data);
}
}
+ inline void reset_kill_query()
+ {
+ if (killed < KILL_CONNECTION)
+ {
+ reset_killed();
+ mysys_var->abort= 0;
+ }
+ }
inline void send_kill_message() const
{
int err= killed_errno();
@@ -2803,6 +3349,27 @@ public:
void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
void restore_active_arena(Query_arena *set, Query_arena *backup);
+ inline void get_binlog_format(enum_binlog_format *format,
+ enum_binlog_format *current_format)
+ {
+ *format= (enum_binlog_format) variables.binlog_format;
+ *current_format= current_stmt_binlog_format;
+ }
+ inline void set_binlog_format(enum_binlog_format format,
+ enum_binlog_format current_format)
+ {
+ DBUG_ENTER("set_binlog_format");
+ variables.binlog_format= format;
+ current_stmt_binlog_format= current_format;
+ DBUG_VOID_RETURN;
+ }
+ inline void set_binlog_format_stmt()
+ {
+ DBUG_ENTER("set_binlog_format_stmt");
+ variables.binlog_format= BINLOG_FORMAT_STMT;
+ current_stmt_binlog_format= BINLOG_FORMAT_STMT;
+ DBUG_VOID_RETURN;
+ }
/*
@todo Make these methods private or remove them completely. Only
decide_logging_format should call them. /Sven
@@ -2833,16 +3400,26 @@ public:
DBUG_VOID_RETURN;
}
+
inline void set_current_stmt_binlog_format_row()
{
DBUG_ENTER("set_current_stmt_binlog_format_row");
current_stmt_binlog_format= BINLOG_FORMAT_ROW;
DBUG_VOID_RETURN;
}
- inline void clear_current_stmt_binlog_format_row()
+ /* Set binlog format temporarily to statement. Returns old format */
+ inline enum_binlog_format set_current_stmt_binlog_format_stmt()
{
- DBUG_ENTER("clear_current_stmt_binlog_format_row");
+ enum_binlog_format orig_format= current_stmt_binlog_format;
+ DBUG_ENTER("set_current_stmt_binlog_format_stmt");
current_stmt_binlog_format= BINLOG_FORMAT_STMT;
+ DBUG_RETURN(orig_format);
+ }
+ inline void restore_stmt_binlog_format(enum_binlog_format format)
+ {
+ DBUG_ENTER("restore_stmt_binlog_format");
+ DBUG_ASSERT(!is_current_stmt_binlog_format_row());
+ current_stmt_binlog_format= format;
DBUG_VOID_RETURN;
}
inline void reset_current_stmt_binlog_format_row()
@@ -2872,7 +3449,7 @@ public:
if (variables.binlog_format == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
else if (temporary_tables == NULL)
- clear_current_stmt_binlog_format_row();
+ set_current_stmt_binlog_format_stmt();
}
DBUG_VOID_RETURN;
}
@@ -2918,8 +3495,13 @@ public:
db= NULL;
}
db_length= db ? new_db_len : 0;
+ bool result= new_db && !db;
mysql_mutex_unlock(&LOCK_thd_data);
- return new_db && !db;
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ if (result)
+ PSI_THREAD_CALL(set_thread_db)(new_db, new_db_len);
+#endif
+ return result;
}
/**
@@ -2941,6 +3523,9 @@ public:
db= new_db;
db_length= new_db_len;
mysql_mutex_unlock(&LOCK_thd_data);
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ PSI_THREAD_CALL(set_thread_db)(new_db, new_db_len);
+#endif
}
}
/*
@@ -2971,6 +3556,7 @@ public:
*/
void push_internal_handler(Internal_error_handler *handler);
+private:
/**
Handle a sql condition.
@param sql_errno the condition error number
@@ -2980,12 +3566,13 @@ public:
@param[out] cond_hdl the sql condition raised, if any
@return true if the condition is handled
*/
- virtual bool handle_condition(uint sql_errno,
- const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
- const char* msg,
- MYSQL_ERROR ** cond_hdl);
+ bool handle_condition(uint sql_errno,
+ const char* sqlstate,
+ Sql_condition::enum_warning_level level,
+ const char* msg,
+ Sql_condition ** cond_hdl);
+public:
/**
Remove the error handler last pushed.
*/
@@ -3035,10 +3622,10 @@ private:
To raise a SQL condition, the code should use the public
raise_error() or raise_warning() methods provided by class THD.
*/
- friend class Signal_common;
- friend class Signal_statement;
- friend class Resignal_statement;
- friend void push_warning(THD*, MYSQL_ERROR::enum_warning_level, uint, const char*);
+ friend class Sql_cmd_common_signal;
+ friend class Sql_cmd_signal;
+ friend class Sql_cmd_resignal;
+ friend void push_warning(THD*, Sql_condition::enum_warning_level, uint, const char*);
friend void my_message_sql(uint, const char *, myf);
/**
@@ -3049,15 +3636,18 @@ private:
@param msg the condition message text
@return The condition raised, or NULL
*/
- MYSQL_ERROR*
+ Sql_condition*
raise_condition(uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg);
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.
@@ -3077,7 +3667,10 @@ public:
{ set_query(CSET_STRING()); }
void set_query_and_id(char *query_arg, uint32 query_length_arg,
CHARSET_INFO *cs, query_id_t new_query_id);
- void set_query_id(query_id_t new_query_id);
+ void set_query_id(query_id_t new_query_id)
+ {
+ query_id= new_query_id;
+ }
void set_open_tables(TABLE *open_tables_arg)
{
mysql_mutex_lock(&LOCK_thd_data);
@@ -3106,9 +3699,11 @@ public:
}
void leave_locked_tables_mode();
int decide_logging_format(TABLE_LIST *tables);
- void binlog_invoker() { m_binlog_invoker= TRUE; }
- bool need_binlog_invoker() { return m_binlog_invoker; }
- void get_definer(LEX_USER *definer);
+
+ enum need_invoker { INVOKER_NONE=0, INVOKER_USER, INVOKER_ROLE};
+ void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; }
+ enum need_invoker need_binlog_invoker() { return m_binlog_invoker; }
+ void get_definer(LEX_USER *definer, bool role);
void set_invoker(const LEX_STRING *user, const LEX_STRING *host)
{
invoker_user= *user;
@@ -3149,6 +3744,28 @@ public:
mysql_mutex_unlock(&LOCK_status);
}
+ wait_for_commit *wait_for_commit_ptr;
+ int wait_for_prior_commit()
+ {
+ if (wait_for_commit_ptr)
+ return wait_for_commit_ptr->wait_for_prior_commit(this);
+ return 0;
+ }
+ void wakeup_subsequent_commits(int wakeup_error)
+ {
+ if (wait_for_commit_ptr)
+ wait_for_commit_ptr->wakeup_subsequent_commits(wakeup_error);
+ }
+ wait_for_commit *suspend_subsequent_commits() {
+ wait_for_commit *suspended= wait_for_commit_ptr;
+ wait_for_commit_ptr= NULL;
+ return suspended;
+ }
+ void resume_subsequent_commits(wait_for_commit *suspended) {
+ DBUG_ASSERT(!wait_for_commit_ptr);
+ wait_for_commit_ptr= suspended;
+ }
+
void mark_transaction_to_rollback(bool all);
private:
@@ -3171,18 +3788,19 @@ private:
tree itself is reused between executions and thus is stored elsewhere.
*/
MEM_ROOT main_mem_root;
- Warning_info main_warning_info;
Diagnostics_area main_da;
+ Diagnostics_area *m_stmt_da;
/**
- It will be set TURE if CURRENT_USER() is called in account management
- statements or default definer is set in CREATE/ALTER SP, SF, Event,
- TRIGGER or VIEW statements.
+ It will be set if CURRENT_USER() or CURRENT_ROLE() is called in account
+ management statements or default definer is set in CREATE/ALTER SP, SF,
+ Event, TRIGGER or VIEW statements.
- Current user will be binlogged into Query_log_event if m_binlog_invoker
- is TRUE; It will be stored into invoker_host and invoker_user by SQL thread.
+ Current user or role will be binlogged into Query_log_event if
+ m_binlog_invoker is not NONE; It will be stored into invoker_host and
+ invoker_user by SQL thread.
*/
- bool m_binlog_invoker;
+ enum need_invoker m_binlog_invoker;
/**
It points to the invoker in the Query_log_event.
@@ -3192,6 +3810,12 @@ private:
*/
LEX_STRING invoker_user;
LEX_STRING invoker_host;
+
+ /* Protect against add/delete of temporary tables in parallel replication */
+ void rgi_lock_temporary_tables();
+ void rgi_unlock_temporary_tables(bool clear);
+ bool rgi_have_temporary_tables();
+public:
/*
Flag, mutex and condition for a thread to wait for a signal from another
thread.
@@ -3202,27 +3826,48 @@ private:
bool wakeup_ready;
mysql_mutex_t LOCK_wakeup_ready;
mysql_cond_t COND_wakeup_ready;
+ /*
+ The GTID assigned to the last commit. If no GTID was assigned to any commit
+ so far, this is indicated by last_commit_gtid.seq_no == 0.
+ */
+ rpl_gtid last_commit_gtid;
+
+ inline void lock_temporary_tables()
+ {
+ if (rgi_slave)
+ rgi_lock_temporary_tables();
+ }
+ inline void unlock_temporary_tables(bool clear)
+ {
+ if (rgi_slave)
+ rgi_unlock_temporary_tables(clear);
+ }
+ inline bool have_temporary_tables()
+ {
+ return (temporary_tables ||
+ (rgi_slave && unlikely(rgi_have_temporary_tables())));
+ }
};
-/** A short cut for thd->stmt_da->set_ok_status(). */
+/** A short cut for thd->get_stmt_da()->set_ok_status(). */
inline void
my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
const char *message= NULL)
{
thd->set_row_count_func(affected_rows);
- thd->stmt_da->set_ok_status(thd, affected_rows, id, message);
+ thd->get_stmt_da()->set_ok_status(affected_rows, id, message);
}
-/** A short cut for thd->stmt_da->set_eof_status(). */
+/** A short cut for thd->get_stmt_da()->set_eof_status(). */
inline void
my_eof(THD *thd)
{
thd->set_row_count_func(-1);
- thd->stmt_da->set_eof_status(thd);
+ thd->get_stmt_da()->set_eof_status(thd);
}
#define tmp_disable_binlog(A) \
@@ -3232,25 +3877,10 @@ my_eof(THD *thd)
#define reenable_binlog(A) (A)->variables.option_bits= tmp_disable_binlog__save_options;}
-/*
- These functions are for making it later easy to add strict
- checking for all date handling.
-*/
-
-const my_bool strict_date_checking= 0;
-
-inline ulong sql_mode_for_dates(THD *thd)
-{
- if (strict_date_checking)
- return (thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES));
- return (thd->variables.sql_mode & MODE_INVALID_DATES);
-}
-
-inline ulong sql_mode_for_dates()
+inline sql_mode_t sql_mode_for_dates(THD *thd)
{
- return sql_mode_for_dates(current_thd);
+ return thd->variables.sql_mode &
+ (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES);
}
/*
@@ -3280,10 +3910,42 @@ public:
class JOIN;
-class select_result :public Sql_alloc {
+/* Pure interface for sending tabular data */
+class select_result_sink: public Sql_alloc
+{
+public:
+ /*
+ send_data returns 0 on ok, 1 on error and -1 if data was ignored, for
+ example for a duplicate row entry written to a temp table.
+ */
+ virtual int send_data(List<Item> &items)=0;
+ virtual ~select_result_sink() {};
+};
+
+
+/*
+ Interface for sending tabular data, together with some other stuff:
+
+ - Primary purpose seems to be seding typed tabular data:
+ = the DDL is sent with send_fields()
+ = the rows are sent with send_data()
+ Besides that,
+ - there seems to be an assumption that the sent data is a result of
+ SELECT_LEX_UNIT *unit,
+ - nest_level is used by SQL parser
+*/
+
+class select_result :public select_result_sink
+{
protected:
THD *thd;
+ /*
+ All descendant classes have their send_data() skip the first
+ unit->offset_limit_cnt rows sent. Select_materialize
+ also uses unit->get_unit_column_types().
+ */
SELECT_LEX_UNIT *unit;
+ /* Something used only by the parser: */
public:
select_result();
virtual ~select_result() {};
@@ -3301,13 +3963,7 @@ public:
virtual uint field_count(List<Item> &fields) const
{ return fields.elements; }
virtual bool send_result_set_metadata(List<Item> &list, uint flags)=0;
- /*
- send_data returns 0 on ok, 1 on error and -1 if data was ignored, for
- example for a duplicate row entry written to a temp table.
- */
- virtual int send_data(List<Item> &items)=0;
virtual bool initialize_tables (JOIN *join=0) { return 0; }
- virtual void send_error(uint errcode,const char *err);
virtual bool send_eof()=0;
/**
Check if this query returns a result set and therefore is allowed in
@@ -3330,6 +3986,57 @@ public:
void begin_dataset() {}
#endif
virtual void update_used_tables() {}
+
+ void reset_offset_limit()
+ {
+ unit->offset_limit_cnt= 0;
+ }
+};
+
+
+/*
+ This is a select_result_sink which simply writes all data into a (temporary)
+ table. Creation/deletion of the table is outside of the scope of the class
+
+ It is aimed at capturing SHOW EXPLAIN output, so:
+ - Unlike select_result class, we don't assume that the sent data is an
+ output of a SELECT_LEX_UNIT (and so we dont apply "LIMIT x,y" from the
+ unit)
+ - We don't try to convert the target table to MyISAM
+*/
+
+class select_result_explain_buffer : public select_result_sink
+{
+public:
+ select_result_explain_buffer(THD *thd_arg, TABLE *table_arg) :
+ thd(thd_arg), dst_table(table_arg) {};
+
+ THD *thd;
+ TABLE *dst_table; /* table to write into */
+
+ /* The following is called in the child thread: */
+ int send_data(List<Item> &items);
+};
+
+
+/*
+ This is a select_result_sink which stores the data in text form.
+*/
+
+class select_result_text_buffer : public select_result_sink
+{
+public:
+ select_result_text_buffer(THD *thd_arg) : thd(thd_arg) {}
+ int send_data(List<Item> &items);
+ bool send_result_set_metadata(List<Item> &fields, uint flag);
+
+ void save_to(String *res);
+private:
+ int append_row(List<Item> &items, bool send_names);
+
+ THD *thd;
+ List<char*> rows;
+ int n_columns;
};
@@ -3383,7 +4090,6 @@ public:
select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L)
{ path[0]=0; }
~select_to_file();
- void send_error(uint errcode,const char *err);
bool send_eof();
void cleanup();
};
@@ -3456,7 +4162,6 @@ class select_insert :public select_result_interceptor {
virtual int send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
virtual bool can_rollback_data() { return 0; }
- void send_error(uint errcode,const char *err);
bool send_eof();
virtual void abort_result_set();
/* not implemented: select_insert is never re-used in prepared statements */
@@ -3475,6 +4180,8 @@ class select_create: public select_insert {
MYSQL_LOCK *m_lock;
/* m_lock or thd->extra_lock */
MYSQL_LOCK **m_plock;
+ bool exit_done;
+
public:
select_create (TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par,
@@ -3486,13 +4193,12 @@ public:
create_info(create_info_par),
select_tables(select_tables_arg),
alter_info(alter_info_arg),
- m_plock(NULL)
+ m_plock(NULL), exit_done(0)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
- void send_error(uint errcode,const char *err);
bool send_eof();
virtual void abort_result_set();
virtual bool can_rollback_data() { return 1; }
@@ -3507,12 +4213,22 @@ 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"
+inline uint tmp_table_max_key_length() { return maria_max_key_length(); }
+inline uint tmp_table_max_key_parts() { return maria_max_key_segments(); }
#else
-#define ENGINE_COLUMNDEF MI_COLUMNDEF
+#define TMP_ENGINE_COLUMNDEF MI_COLUMNDEF
+#define TMP_ENGINE_HTON myisam_hton
+#define TMP_ENGINE_NAME "MyISAM"
+inline uint tmp_table_max_key_length() { return MI_MAX_KEY_LENGTH; }
+inline uint tmp_table_max_key_parts() { return MI_MAX_KEY_SEG; }
#endif
/*
@@ -3535,7 +4251,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;
/**
@@ -3790,13 +4506,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 ---------- */
@@ -3885,7 +4601,7 @@ public:
table.str= internal_table_name;
table.length=1;
}
- bool is_derived_table() const { return test(sel); }
+ bool is_derived_table() const { return MY_TEST(sel); }
inline void change_db(char *db_name)
{
db.str= db_name; db.length= (uint) strlen(db_name);
@@ -3911,6 +4627,8 @@ class user_var_entry
DTCollation collation;
};
+user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
+ bool create_if_not_exists);
/*
Unique -- class for unique (removing of duplicates).
@@ -3938,6 +4656,7 @@ class Unique :public Sql_alloc
uint min_dupl_count; /* Minimum number of occurences of element required for
it to be written to record_pointers.
always 0 for unions, > 0 for intersections */
+ bool with_counters;
bool merge(TABLE *table, uchar *buff, bool without_last_merge);
@@ -4011,7 +4730,7 @@ class multi_delete :public select_result_interceptor
bool delete_while_scanning;
/*
error handling (rollback and binlogging) can happen in send_eof()
- so that afterward send_error() needs to find out that.
+ so that afterward abort_result_set() needs to find out that.
*/
bool error_handled;
@@ -4021,7 +4740,6 @@ public:
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
- void send_error(uint errcode,const char *err);
int do_deletes();
int do_table_deletes(TABLE *table, bool ignore);
bool send_eof();
@@ -4057,10 +4775,12 @@ class multi_update :public select_result_interceptor
bool ignore;
/*
error handling (rollback and binlogging) can happen in send_eof()
- so that afterward send_error() needs to find out that.
+ so that afterward abort_result_set() needs to find out that.
*/
bool error_handled;
-
+
+ /* Need this to protect against multiple prepare() calls */
+ bool prepared;
public:
multi_update(TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
List<Item> *fields, List<Item> *values,
@@ -4069,7 +4789,6 @@ public:
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
- void send_error(uint errcode,const char *err);
int do_updates();
bool send_eof();
inline ha_rows num_found()
@@ -4185,6 +4904,47 @@ 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 << 16)
+
+/**
+ Statement that inserts new rows (INSERT, REPLACE, LOAD, ALTER TABLE)
+*/
+#define CF_INSERTS_DATA (1U << 17)
+
+/**
+ Statement that updates existing rows (UPDATE, multi-update)
+*/
+#define CF_UPDATES_DATA (1U << 18)
+
/* Bits in server_command_flags */
/**
@@ -4241,112 +5001,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)
{
@@ -4358,42 +5012,9 @@ 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);
- if (!error)
- update_rows_read();
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -4409,24 +5030,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 */