diff options
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r-- | sql/sql_class.h | 827 |
1 files changed, 672 insertions, 155 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h index 57ff65cb416..f64e7cb5a3f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -29,13 +29,14 @@ #include "mdl.h" #include "field.h" // Create_field #include "probes_mysql.h" -#include "sql_locale.h" /* my_locale_st */ -#include "sql_profile.h" /* PROFILING */ -#include "scheduler.h" /* thd_scheduler */ -#include "protocol.h" /* Protocol_text, Protocol_binary */ -#include "violite.h" /* vio_is_connected */ -#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, - THR_LOCK_INFO */ +#include "sql_locale.h" /* my_locale_st */ +#include "sql_profile.h" /* PROFILING */ +#include "scheduler.h" /* thd_scheduler */ +#include "protocol.h" /* Protocol_text, Protocol_binary */ +#include "violite.h" /* vio_is_connected */ +#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */ +#include "thr_timer.h" + #include "sql_digest_stream.h" // sql_digest_state #include <mysql/psi/mysql_stage.h> @@ -51,12 +52,13 @@ void set_thd_stage_info(void *thd, 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__) + (thd)->enter_stage(&stage, __func__, __FILE__, __LINE__) #include "my_apc.h" #include "rpl_gtid.h" +#include "wsrep_mysqld.h" class Reprepare_observer; class Relay_log_info; @@ -64,7 +66,6 @@ struct rpl_group_info; class Rpl_filter; class Query_log_event; class Load_log_event; -class Slave_log_event; class sp_rcontext; class sp_cache; class Lex_input_stream; @@ -92,6 +93,16 @@ enum enum_mark_columns { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE}; enum enum_filetype { FILETYPE_CSV, FILETYPE_XML }; +enum enum_binlog_row_image { + /** PKE in the before image and changed columns in the after image */ + BINLOG_ROW_IMAGE_MINIMAL= 0, + /** Whenever possible, before and after image contain all columns except blobs. */ + BINLOG_ROW_IMAGE_NOBLOB= 1, + /** All columns in both before and after image. */ + BINLOG_ROW_IMAGE_FULL= 2 +}; + + /* Bits for different SQL modes modes (including ANSI mode) */ #define MODE_REAL_AS_FLOAT (1ULL << 0) #define MODE_PIPES_AS_CONCAT (1ULL << 1) @@ -277,7 +288,7 @@ public: }; -class Key :public Sql_alloc { +class Key :public Sql_alloc, public DDL_options { public: enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY}; enum Keytype type; @@ -286,23 +297,30 @@ 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, + ha_key_alg algorithm_arg, bool generated_arg, DDL_options_st ddl_options) + :DDL_options(ddl_options), + type(type_par), key_create_info(default_key_create_info), + name(name_arg), option_list(NULL), generated(generated_arg) + { + key_create_info.algorithm= algorithm_arg; + } + 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, 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), - create_if_not_exists(if_not_exists_opt) + engine_option_value *create_opt, DDL_options_st ddl_options) + :DDL_options(ddl_options), + type(type_par), key_create_info(*key_info_arg), columns(cols), + name(name_arg), option_list(create_opt), generated(generated_arg) {} 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, bool if_not_exists_opt) - :type(type_par), key_create_info(*key_info_arg), columns(cols), - option_list(create_opt), generated(generated_arg), - create_if_not_exists(if_not_exists_opt) + engine_option_value *create_opt, DDL_options_st ddl_options) + :DDL_options(ddl_options), + type(type_par), key_create_info(*key_info_arg), columns(cols), + option_list(create_opt), generated(generated_arg) { name.str= (char *)name_arg; name.length= name_len_arg; @@ -335,9 +353,9 @@ public: 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) + DDL_options ddl_options) :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL, - if_not_exists_opt), + ddl_options), 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) @@ -449,20 +467,21 @@ enum killed_state */ ABORT_QUERY= 6, ABORT_QUERY_HARD= 7, + KILL_TIMEOUT= 8, + KILL_TIMEOUT_HARD= 9, /* All of the following killed states will kill the connection KILL_CONNECTION must be the first of these and it must start with an even number (becasue of HARD bit)! */ - KILL_CONNECTION= 8, - KILL_CONNECTION_HARD= 9, - KILL_SYSTEM_THREAD= 10, - KILL_SYSTEM_THREAD_HARD= 11, - KILL_SERVER= 12, - KILL_SERVER_HARD= 13 + KILL_CONNECTION= 10, + KILL_CONNECTION_HARD= 11, + KILL_SYSTEM_THREAD= 12, + KILL_SYSTEM_THREAD_HARD= 13, + KILL_SERVER= 14, + KILL_SERVER_HARD= 15 }; -extern int killed_errno(killed_state killed); #define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT)) enum killed_type @@ -474,7 +493,6 @@ enum killed_type #include "sql_lex.h" /* Must be here */ -extern LEX_STRING sql_statement_names[(uint) SQLCOM_END + 1]; class Delayed_insert; class select_result; class Time_zone; @@ -508,6 +526,7 @@ typedef struct system_variables ulonglong max_heap_table_size; ulonglong tmp_table_size; ulonglong long_query_time; + ulonglong max_statement_time; ulonglong optimizer_switch; 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 @@ -520,6 +539,7 @@ typedef struct system_variables ulonglong sortbuff_size; ulonglong group_concat_max_len; ulonglong default_regex_flags; + ulonglong max_mem_used; /** Place holders to store Multi-source variables in sys_var.cc during @@ -575,10 +595,8 @@ typedef struct system_variables /* Flags for slow log filtering */ ulong log_slow_rate_limit; ulong binlog_format; ///< binlog format for this thd (see enum_binlog_format) + ulong binlog_row_image; ulong progress_report_time; - my_bool binlog_annotate_row_events; - my_bool binlog_direct_non_trans_update; - my_bool sql_log_bin; ulong completion_type; ulong query_cache_type; ulong tx_isolation; @@ -603,7 +621,6 @@ typedef struct system_variables my_bool tx_read_only; my_bool low_priority_updates; my_bool query_cache_wlock_invalidate; - my_bool engine_condition_pushdown; my_bool keep_files_on_create; my_bool old_mode; @@ -611,8 +628,19 @@ typedef struct system_variables my_bool old_passwords; my_bool big_tables; my_bool query_cache_strip_comments; + my_bool sql_log_slow; + my_bool sql_log_bin; + /* + A flag to help detect whether binary logging was temporarily disabled + (see tmp_disable_binlog(A) macro). + */ + my_bool sql_log_bin_off; + my_bool binlog_annotate_row_events; + my_bool binlog_direct_non_trans_update; plugin_ref table_plugin; + plugin_ref tmp_table_plugin; + plugin_ref enforced_table_plugin; /* Only charset part of these variables is sensible */ CHARSET_INFO *character_set_filesystem; @@ -629,6 +657,8 @@ typedef struct system_variables /* Error messages */ MY_LOCALE *lc_messages; + const char **errmsgs; /* lc_messages->errmsg->errmsgs */ + /* Locale Support */ MY_LOCALE *lc_time_names; @@ -640,7 +670,13 @@ typedef struct system_variables ulong wt_timeout_short, wt_deadlock_search_depth_short; ulong wt_timeout_long, wt_deadlock_search_depth_long; - double long_query_time_double; + my_bool wsrep_on; + my_bool wsrep_causal_reads; + my_bool wsrep_dirty_reads; + uint wsrep_sync_wait; + ulong wsrep_retry_autocommit; + ulong wsrep_OSU_method; + double long_query_time_double, max_statement_time_double; my_bool pseudo_slave_mode; @@ -654,8 +690,19 @@ typedef struct system_variables typedef struct system_status_var { - ulong com_other; ulong com_stat[(uint) SQLCOM_END]; + ulong com_create_tmp_table; + ulong com_drop_tmp_table; + ulong com_other; + + ulong com_stmt_prepare; + ulong com_stmt_reprepare; + ulong com_stmt_execute; + ulong com_stmt_send_long_data; + ulong com_stmt_fetch; + ulong com_stmt_reset; + ulong com_stmt_close; + ulong com_register_slave; ulong created_tmp_disk_tables_; ulong created_tmp_tables_; @@ -713,14 +760,6 @@ typedef struct system_status_var ulong filesort_rows_; ulong filesort_scan_count_; ulong filesort_pq_sorts_; - /* Prepared statements and binary protocol */ - ulong com_stmt_prepare; - ulong com_stmt_reprepare; - ulong com_stmt_execute; - ulong com_stmt_send_long_data; - ulong com_stmt_fetch; - ulong com_stmt_reset; - ulong com_stmt_close; /* Features used */ ulong feature_dynamic_columns; /* +1 when creating a dynamic column */ @@ -732,9 +771,15 @@ typedef struct system_status_var ulong feature_trigger; /* +1 opening a table with triggers */ ulong feature_xml; /* +1 when XPATH is used */ + /* From MASTER_GTID_WAIT usage */ + ulonglong master_gtid_wait_timeouts; /* Number of timeouts */ + ulonglong master_gtid_wait_time; /* Time in microseconds */ + ulonglong master_gtid_wait_count; + ulong empty_queries; ulong access_denied_errors; ulong lost_connections; + ulong max_statement_time_exceeded; /* Number of statements sent from the client */ @@ -754,7 +799,10 @@ typedef struct system_status_var double last_query_cost; double cpu_time, busy_time; /* Don't initialize */ - volatile int64 memory_used; /* This shouldn't be accumulated */ + /* Memory used for thread local storage */ + volatile int64 local_memory_used; + /* Memory allocated for global usage */ + volatile int64 global_memory_used; } STATUS_VAR; /* @@ -764,7 +812,7 @@ typedef struct system_status_var */ #define last_system_status_var questions -#define last_cleared_system_status_var memory_used +#define last_cleared_system_status_var local_memory_used /* Global status variables @@ -778,6 +826,20 @@ 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); +/* + Update global_memory_used. We have to do this with atomic_add as the + global value can change outside of LOCK_status. +*/ +inline void update_global_memory_status(int64 size) +{ + DBUG_PRINT("info", ("global memory_used: %lld size: %lld", + (longlong) global_status_var.global_memory_used, + size)); + // workaround for gcc 4.2.4-1ubuntu4 -fPIE (from DEB_BUILD_HARDENING=1) + int64 volatile * volatile ptr= &global_status_var.global_memory_used; + my_atomic_add64_explicit(ptr, size, MY_MEMORY_ORDER_RELAXED); +} + /** Get collation by name, send error to client on failure. @param name Collation name @@ -805,6 +867,11 @@ mysqld_collation_get_by_name(const char *name, return cs; } +inline bool is_supported_parser_charset(CHARSET_INFO *cs) +{ + return MY_TEST(cs->mbminlen == 1); +} + #ifdef MYSQL_SERVER void free_tmp_table(THD *thd, TABLE *entry); @@ -903,6 +970,19 @@ public: }; +class Query_arena_memroot: public Query_arena, public Sql_alloc +{ +public: + Query_arena_memroot(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : + Query_arena(mem_root_arg, state_arg) + {} + Query_arena_memroot() : Query_arena() + {} + + virtual ~Query_arena_memroot() {} +}; + + class Server_side_cursor; /** @@ -1088,24 +1168,24 @@ struct st_savepoint { enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY}; extern const char *xa_state_names[]; +class XID_cache_element; typedef struct st_xid_state { /* For now, this is only used to catch duplicated external xids */ XID xid; // transaction identifier enum xa_states xa_state; // used by external XA only - bool in_thd; /* Error reported by the Resource Manager (RM) to the Transaction Manager. */ uint rm_error; + XID_cache_element *xid_cache_element; } XID_STATE; -extern mysql_mutex_t LOCK_xid_cache; -extern HASH xid_cache; -bool xid_cache_init(void); +void xid_cache_init(void); void xid_cache_free(void); -XID_STATE *xid_cache_search(XID *xid); +XID_STATE *xid_cache_search(THD *thd, XID *xid); bool xid_cache_insert(XID *xid, enum xa_states xa_state); -bool xid_cache_insert(XID_STATE *xid_state); -void xid_cache_delete(XID_STATE *xid_state); +bool xid_cache_insert(THD *thd, XID_STATE *xid_state); +void xid_cache_delete(THD *thd, XID_STATE *xid_state); +int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *argument); /** @class Security_context @@ -1367,11 +1447,11 @@ enum enum_thread_type SYSTEM_THREAD_DELAYED_INSERT= 1, SYSTEM_THREAD_SLAVE_IO= 2, SYSTEM_THREAD_SLAVE_SQL= 4, - SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8, - SYSTEM_THREAD_EVENT_SCHEDULER= 16, - SYSTEM_THREAD_EVENT_WORKER= 32, - SYSTEM_THREAD_BINLOG_BACKGROUND= 64, - SYSTEM_THREAD_SLAVE_INIT= 128, + SYSTEM_THREAD_EVENT_SCHEDULER= 8, + SYSTEM_THREAD_EVENT_WORKER= 16, + SYSTEM_THREAD_BINLOG_BACKGROUND= 32, + SYSTEM_THREAD_SLAVE_INIT= 64, + SYSTEM_THREAD_SLAVE_BACKGROUND= 128 }; inline char const * @@ -1384,9 +1464,9 @@ show_system_thread(enum_thread_type thread) RETURN_NAME_AS_STRING(SYSTEM_THREAD_DELAYED_INSERT); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_IO); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_SQL); - RETURN_NAME_AS_STRING(SYSTEM_THREAD_NDBCLUSTER_BINLOG); RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_SCHEDULER); RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER); + RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_INIT); default: sprintf(buf, "<UNKNOWN SYSTEM THREAD: %d>", thread); return buf; @@ -1743,7 +1823,7 @@ struct wait_for_commit return wakeup_error; } } - void wakeup_subsequent_commits(int wakeup_error) + void wakeup_subsequent_commits(int wakeup_error_arg) { /* Do the check inline, so only the wakeup case takes the cost of a function @@ -1758,7 +1838,7 @@ struct wait_for_commit prevent a waiter from arriving just after releasing the lock. */ if (subsequent_commits_list) - wakeup_subsequent_commits2(wakeup_error); + wakeup_subsequent_commits2(wakeup_error_arg); } void unregister_wait_for_prior_commit() { @@ -1843,7 +1923,7 @@ public: rpl_sql_thread_info *rpl_sql_info; } system_thread_info; - void reset_for_next_command(); + void reset_for_next_command(bool do_clear_errors= 1); /* Constant for THD::where initialization in the beginning of every query. @@ -1899,6 +1979,8 @@ public: Is locked when THD is deleted. */ mysql_mutex_t LOCK_thd_data; + /* Protect kill information */ + mysql_mutex_t LOCK_thd_kill; /* all prepared statements and cursors of this connection */ Statement_map stmt_map; @@ -1948,10 +2030,28 @@ private: 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 unsigned int calling_line) + { + DBUG_PRINT("THD::enter_stage", ("%s:%d", calling_file, calling_line)); + DBUG_ASSERT(stage); + m_current_stage_key= stage->m_key; + proc_info= stage->m_name; +#if defined(ENABLED_PROFILING) + profiling.status_change(stage->m_name, calling_func, calling_file, + calling_line); +#endif +#ifdef HAVE_PSI_THREAD_INTERFACE + MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line); +#endif + } + + void backup_stage(PSI_stage_info *stage) + { + stage->m_key= m_current_stage_key; + stage->m_name= proc_info; + } const char *get_proc_info() const { return proc_info; } @@ -2061,14 +2161,12 @@ public: int binlog_write_table_map(TABLE *table, bool is_transactional, my_bool *with_annotate= 0); int binlog_write_row(TABLE* table, bool is_transactional, - MY_BITMAP const* cols, size_t colcnt, const uchar *buf); int binlog_delete_row(TABLE* table, bool is_transactional, - MY_BITMAP const* cols, size_t colcnt, const uchar *buf); int binlog_update_row(TABLE* table, bool is_transactional, - MY_BITMAP const* cols, size_t colcnt, const uchar *old_data, const uchar *new_data); + static void binlog_prepare_row_images(TABLE* table); void set_server_id(uint32 sid) { variables.server_id = sid; } @@ -2077,11 +2175,9 @@ public: */ template <class RowsEventT> Rows_log_event* binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id, - MY_BITMAP const* cols, - size_t colcnt, size_t needed, bool is_transactional, - RowsEventT* hint); + RowsEventT* hint); Rows_log_event* binlog_get_pending_rows_event(bool is_transactional) const; void binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional); inline int binlog_flush_pending_rows_event(bool stmt_end) @@ -2520,7 +2616,7 @@ public: void check_limit_rows_examined() { if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt) - killed= ABORT_QUERY; + set_killed(ABORT_QUERY); } USER_CONN *user_connect; @@ -2567,6 +2663,7 @@ public: ulong query_plan_fsort_passes; pthread_t real_id; /* For debugging */ my_thread_id thread_id; + uint32 os_thread_id; uint tmp_table, global_disable_checkpoint; uint server_status,open_options; enum enum_thread_type system_thread; @@ -2620,6 +2717,16 @@ public: */ killed_state volatile killed; + /* + The following is used if one wants to have a specific error number and + text for the kill + */ + struct err_info + { + int no; + const char msg[256]; + } *killed_err; + /* See also thd_killed() */ inline bool check_killed() { @@ -2651,7 +2758,7 @@ public: can not continue. In particular, disables activation of CONTINUE or EXIT handlers of stored routines. Reset in the end of processing of the current user request, in - @see mysql_reset_thd_for_next_command(). + @see THD::reset_for_next_command(). */ bool is_fatal_error; /** @@ -2753,10 +2860,13 @@ public: union { my_bool my_bool_value; + int int_value; + uint uint_value; long long_value; ulong ulong_value; ulonglong ulonglong_value; double double_value; + void *ptr_value; } sys_var_tmp; struct { @@ -2816,7 +2926,8 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(); + THD(bool is_wsrep_applier= false); + ~THD(); void init(void); @@ -2895,7 +3006,10 @@ public: mysql_mutex_assert_owner(mutex); mysys_var->current_mutex = mutex; mysys_var->current_cond = cond; - enter_stage(stage, old_stage, src_function, src_file, src_line); + if (old_stage) + backup_stage(old_stage); + if (stage) + enter_stage(stage, src_function, src_file, src_line); } inline void exit_cond(const PSI_stage_info *stage, const char *src_function, const char *src_file, @@ -2911,7 +3025,8 @@ public: mysql_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex = 0; mysys_var->current_cond = 0; - enter_stage(stage, NULL, src_function, src_file, src_line); + if (stage) + enter_stage(stage, src_function, src_file, src_line); mysql_mutex_unlock(&mysys_var->mutex); return; } @@ -2946,16 +3061,15 @@ public: // 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 bool backslash_escapes() const + { + return !MY_TEST(variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES); + } 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; } @@ -3114,17 +3228,61 @@ public: return make_lex_string(lex_str, str, length); } + // Allocate LEX_STRING for character set conversion + bool alloc_lex_string(LEX_STRING *dst, uint length) + { + if ((dst->str= (char*) alloc(length))) + return false; + dst->length= 0; // Safety + return true; // EOM + } bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, const char *from, uint from_length, CHARSET_INFO *from_cs); + /* + Convert a strings between character sets. + Uses my_convert_fix(), which uses an mb_wc .. mc_mb loop internally. + dstcs and srccs cannot be &my_charset_bin. + */ + bool convert_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, + CHARSET_INFO *srccs, const char *src, uint src_length, + String_copier *status); + + /* + Same as above, but additionally sends ER_INVALID_CHARACTER_STRING + in case of bad byte sequences or Unicode conversion problems. + */ + bool convert_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, + CHARSET_INFO *srccs, + const char *src, uint src_length); + + /* + If either "dstcs" or "srccs" is &my_charset_bin, + then performs native copying using cs->cset->copy_fix(). + Otherwise, performs Unicode conversion using convert_fix(). + */ + bool copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, + CHARSET_INFO *srccs, const char *src, uint src_length, + String_copier *status); + + /* + Same as above, but additionally sends ER_INVALID_CHARACTER_STRING + in case of bad byte sequences or Unicode conversion problems. + */ + bool copy_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, + CHARSET_INFO *srccs, const char *src, uint src_length); bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs); void add_changed_table(TABLE *table); 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); + int send_explain_fields(select_result *result, uint8 explain_flags, + bool is_analyze); + void make_explain_field_list(List<Item> &field_list, uint8 explain_flags, + bool is_analyze); + void make_explain_json_field_list(List<Item> &field_list, bool is_analyze); + /** Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we @@ -3133,18 +3291,18 @@ public: @todo: To silence an error, one should use Internal_error_handler mechanism. Issuing an error that can be possibly later "cleared" is not compatible with other installed error handlers and audit plugins. - In future this function will be removed. */ - inline void clear_error() + inline void clear_error(bool clear_diagnostics= 0) { DBUG_ENTER("clear_error"); - if (get_stmt_da()->is_error()) + if (get_stmt_da()->is_error() || clear_diagnostics) 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 + reset_killed(); DBUG_VOID_RETURN; } + #ifndef EMBEDDED_LIBRARY inline bool vio_ok() const { return net.vio != 0; } /** Return FALSE if connection to client is broken. */ @@ -3254,10 +3412,54 @@ public: state after execution of a non-prepared SQL statement. */ void end_statement(); - inline int killed_errno() const + + /* + Mark thread to be killed, with optional error number and string. + string is not released, so it has to be allocted on thd mem_root + or be a global string + + Ensure that we don't replace a kill with a lesser one. For example + if user has done 'kill_connection' we shouldn't replace it with + KILL_QUERY. + */ + inline void set_killed(killed_state killed_arg, + int killed_errno_arg= 0, + const char *killed_err_msg_arg= 0) + { + mysql_mutex_lock(&LOCK_thd_kill); + set_killed_no_mutex(killed_arg, killed_errno_arg, killed_err_msg_arg); + mysql_mutex_unlock(&LOCK_thd_kill); + } + /* + This is only used by THD::awake where we need to keep the lock mutex + locked over some time. + It's ok to have this inline, as in most cases killed_errno_arg will + be a constant 0 and most of the function will disappear. + */ + inline void set_killed_no_mutex(killed_state killed_arg, + int killed_errno_arg= 0, + const char *killed_err_msg_arg= 0) { - return ::killed_errno(killed); + if (killed <= killed_arg) + { + killed= killed_arg; + if (killed_errno_arg) + { + /* + If alloc fails, we only remember the killed flag. + The worst things that can happen is that we get + a suboptimal error message. + */ + if ((killed_err= (err_info*) alloc(sizeof(*killed_err)))) + { + killed_err->no= killed_errno_arg; + ::strmake((char*) killed_err->msg, killed_err_msg_arg, + sizeof(killed_err->msg)-1); + } + } + } } + int killed_errno(); inline void reset_killed() { /* @@ -3266,9 +3468,10 @@ public: */ if (killed != NOT_KILLED) { - mysql_mutex_lock(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_kill); killed= NOT_KILLED; - mysql_mutex_unlock(&LOCK_thd_data); + killed_err= 0; + mysql_mutex_unlock(&LOCK_thd_kill); } } inline void reset_kill_query() @@ -3279,11 +3482,14 @@ public: mysys_var->abort= 0; } } - inline void send_kill_message() const + inline void send_kill_message() { + mysql_mutex_lock(&LOCK_thd_kill); int err= killed_errno(); if (err) - my_message(err, ER(err), MYF(0)); + my_message(err, killed_err ? killed_err->msg : ER_THD(this, err), + MYF(0)); + mysql_mutex_unlock(&LOCK_thd_kill); } /* return TRUE if we will abort query if we make a warning now */ inline bool really_abort_on_warning() @@ -3345,8 +3551,7 @@ public: tests fail and so force them to propagate the lex->binlog_row_based_if_mixed upwards to the caller. */ - if ((variables.binlog_format == BINLOG_FORMAT_MIXED) && - (in_sub_stmt == 0)) + if ((wsrep_binlog_format() == BINLOG_FORMAT_MIXED) && (in_sub_stmt == 0)) set_current_stmt_binlog_format_row(); DBUG_VOID_RETURN; @@ -3397,7 +3602,7 @@ public: show_system_thread(system_thread))); if (in_sub_stmt == 0) { - if (variables.binlog_format == BINLOG_FORMAT_ROW) + if (wsrep_binlog_format() == BINLOG_FORMAT_ROW) set_current_stmt_binlog_format_row(); else if (temporary_tables == NULL) set_current_stmt_binlog_format_stmt(); @@ -3596,7 +3801,13 @@ private: public: /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); - void set_command(enum enum_server_command command); + void set_command(enum enum_server_command command) + { + m_command= command; +#ifdef HAVE_PSI_THREAD_INTERFACE + PSI_STATEMENT_CALL(set_thread_command)(m_command); +#endif + } inline enum enum_server_command get_command() const { return m_command; } @@ -3613,7 +3824,16 @@ public: { set_query(CSET_STRING(query_arg, query_length_arg, charset())); } - void set_query(const CSET_STRING &str); /* Mutex protected */ + void 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_THREAD_CALL(set_thread_info)(query(), query_length()); +#endif + } void reset_query() /* Mutex protected */ { set_query(CSET_STRING()); } void set_query_and_id(char *query_arg, uint32 query_length_arg, @@ -3688,9 +3908,11 @@ public: void add_status_to_global() { + DBUG_ASSERT(status_in_global == 0); mysql_mutex_lock(&LOCK_status); add_to_status(&global_status_var, &status_var); /* Mark that this THD status has already been added in global status */ + status_var.global_memory_used= 0; status_in_global= 1; mysql_mutex_unlock(&LOCK_status); } @@ -3778,8 +4000,8 @@ public: 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. + 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; @@ -3798,6 +4020,105 @@ public: return (temporary_tables || (rgi_slave && unlikely(rgi_have_temporary_tables()))); } + + LF_PINS *tdc_hash_pins; + LF_PINS *xid_hash_pins; + bool fix_xid_hash_pins(); + + inline ulong wsrep_binlog_format() const + { + return WSREP_FORMAT(variables.binlog_format); + } + +#ifdef WITH_WSREP + const bool wsrep_applier; /* dedicated slave applier thread */ + bool wsrep_applier_closing; /* applier marked to close */ + bool wsrep_client_thread; /* to identify client threads*/ + bool wsrep_PA_safe; + bool wsrep_converted_lock_session; + bool wsrep_apply_toi; /* applier processing in TOI */ + enum wsrep_exec_mode wsrep_exec_mode; + query_id_t wsrep_last_query_id; + enum wsrep_query_state wsrep_query_state; + enum wsrep_conflict_state wsrep_conflict_state; + mysql_mutex_t LOCK_wsrep_thd; + wsrep_trx_meta_t wsrep_trx_meta; + uint32 wsrep_rand; + Relay_log_info *wsrep_rli; + rpl_group_info *wsrep_rgi; + wsrep_ws_handle_t wsrep_ws_handle; + ulong wsrep_retry_counter; // of autocommit + char *wsrep_retry_query; + size_t wsrep_retry_query_len; + enum enum_server_command wsrep_retry_command; + enum wsrep_consistency_check_mode + wsrep_consistency_check; + int wsrep_mysql_replicated; + const char *wsrep_TOI_pre_query; /* a query to apply before + the actual TOI query */ + size_t wsrep_TOI_pre_query_len; + wsrep_po_handle_t wsrep_po_handle; + size_t wsrep_po_cnt; +#ifdef GTID_SUPPORT + rpl_sid wsrep_po_sid; +#endif /* GTID_SUPPORT */ + void *wsrep_apply_format; + char wsrep_info[128]; /* string for dynamic proc info */ + /* + When enabled, do not replicate/binlog updates from the current table that's + being processed. At the moment, it is used to keep mysql.gtid_slave_pos + table updates from being replicated to other nodes via galera replication. + */ + bool wsrep_ignore_table; + wsrep_gtid_t wsrep_sync_wait_gtid; + ulong wsrep_affected_rows; + bool wsrep_replicate_GTID; + bool wsrep_skip_wsrep_GTID; +#endif /* WITH_WSREP */ + + /* Handling of timeouts for commands */ + thr_timer_t query_timer; +public: + void set_query_timer() + { +#ifndef EMBEDDED_LIBRARY + /* + Don't start a query timer if + - If timeouts are not set + - if we are in a stored procedure or sub statement + - If this is a slave thread + - If we already have set a timeout (happens when running prepared + statements that calls mysql_execute_command()) + */ + if (!variables.max_statement_time || spcont || in_sub_stmt || + slave_thread || query_timer.expired == 0) + return; + thr_timer_settime(&query_timer, variables.max_statement_time); +#endif + } + void reset_query_timer() + { +#ifndef EMBEDDED_LIBRARY + if (spcont || in_sub_stmt || slave_thread) + return; + if (!query_timer.expired) + thr_timer_end(&query_timer); +#endif + } + void restore_set_statement_var() + { + main_lex.restore_set_statement_var(); + } + /* Copy relevant `stmt` transaction flags to `all` transaction. */ + void merge_unsafe_rollback_flags() + { + if (transaction.stmt.modified_non_trans_table) + transaction.all.modified_non_trans_table= TRUE; + transaction.all.m_unsafe_rollback_flags|= + (transaction.stmt.m_unsafe_rollback_flags & + (THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE | + THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL)); + } }; @@ -3821,11 +4142,14 @@ my_eof(THD *thd) thd->get_stmt_da()->set_eof_status(thd); } -#define tmp_disable_binlog(A) \ +#define tmp_disable_binlog(A) \ {ulonglong tmp_disable_binlog__save_options= (A)->variables.option_bits; \ - (A)->variables.option_bits&= ~OPTION_BIN_LOG + (A)->variables.option_bits&= ~OPTION_BIN_LOG; \ + (A)->variables.sql_log_bin_off= 1; -#define reenable_binlog(A) (A)->variables.option_bits= tmp_disable_binlog__save_options;} +#define reenable_binlog(A) \ + (A)->variables.option_bits= tmp_disable_binlog__save_options; \ + (A)->variables.sql_log_bin_off= 0;} inline sql_mode_t sql_mode_for_dates(THD *thd) @@ -3865,6 +4189,8 @@ class JOIN; class select_result_sink: public Sql_alloc { public: + THD *thd; + select_result_sink(THD *thd_arg): thd(thd_arg) {} /* 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. @@ -3889,7 +4215,6 @@ public: 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 @@ -3898,8 +4223,25 @@ protected: SELECT_LEX_UNIT *unit; /* Something used only by the parser: */ public: - select_result(); + select_result(THD *thd_arg): select_result_sink(thd_arg) {} virtual ~select_result() {}; + /** + Change wrapped select_result. + + Replace the wrapped result object with new_result and call + prepare() and prepare2() on new_result. + + This base class implementation doesn't wrap other select_results. + + @param new_result The new result object to wrap around + + @retval false Success + @retval true Error + */ + virtual bool change_result(select_result *new_result) + { + return false; + } virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u) { unit= u; @@ -3942,6 +4284,14 @@ public: { unit->offset_limit_cnt= 0; } + + /* + This returns + - FALSE if the class sends output row to the client + - TRUE if the output is set elsewhere (a file, @variable, or table). + Currently all intercepting classes derive from select_result_interceptor. + */ + virtual bool is_result_interceptor()=0; }; @@ -3960,9 +4310,8 @@ 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) {}; + select_result_sink(thd_arg), dst_table(table_arg) {}; - THD *thd; TABLE *dst_table; /* table to write into */ /* The following is called in the child thread: */ @@ -3972,12 +4321,14 @@ public: /* This is a select_result_sink which stores the data in text form. + + It is only used to save EXPLAIN output. */ class select_result_text_buffer : public select_result_sink { public: - select_result_text_buffer(THD *thd_arg) : thd(thd_arg) {} + select_result_text_buffer(THD *thd_arg): select_result_sink(thd_arg) {} int send_data(List<Item> &items); bool send_result_set_metadata(List<Item> &fields, uint flag); @@ -3985,7 +4336,6 @@ public: private: int append_row(List<Item> &items, bool send_names); - THD *thd; List<char*> rows; int n_columns; }; @@ -4000,14 +4350,24 @@ private: class select_result_interceptor: public select_result { public: - select_result_interceptor() + select_result_interceptor(THD *thd_arg): + select_result(thd_arg), suppress_my_ok(false) { DBUG_ENTER("select_result_interceptor::select_result_interceptor"); - DBUG_PRINT("enter", ("this 0x%lx", (ulong) this)); + DBUG_PRINT("enter", ("this %p", this)); DBUG_VOID_RETURN; } /* Remove gcc warning */ uint field_count(List<Item> &fields) const { return 0; } bool send_result_set_metadata(List<Item> &fields, uint flag) { return FALSE; } + bool is_result_interceptor() { return true; } + + /* + Instruct the object to not call my_ok(). Client output will be handled + elsewhere. (this is used by ANALYZE $stmt feature). + */ + void disable_my_ok_calls() { suppress_my_ok= true; } +protected: + bool suppress_my_ok; }; @@ -4019,13 +4379,31 @@ class select_send :public select_result { */ bool is_result_set_started; public: - select_send() :is_result_set_started(FALSE) {} + select_send(THD *thd_arg): + select_result(thd_arg), is_result_set_started(FALSE) {} bool send_result_set_metadata(List<Item> &list, uint flags); int send_data(List<Item> &items); bool send_eof(); virtual bool check_simple_select() const { return FALSE; } void abort_result_set(); virtual void cleanup(); + bool is_result_interceptor() { return false; } +}; + + +/* + We need this class, because select_send::send_eof() will call ::my_eof. + + See also class Protocol_discard. +*/ + +class select_send_analyze : public select_send +{ + bool send_result_set_metadata(List<Item> &list, uint flags) { return 0; } + bool send_eof() { return 0; } + void abort_result_set() {} +public: + select_send_analyze(THD *thd_arg): select_send(thd_arg) {} }; @@ -4038,7 +4416,8 @@ protected: char path[FN_REFLEN]; public: - select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L) + select_to_file(THD *thd_arg, sql_exchange *ex): + select_result_interceptor(thd_arg), exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); bool send_eof(); @@ -4080,7 +4459,7 @@ class select_export :public select_to_file { bool fixed_row_size; CHARSET_INFO *write_cs; // output charset public: - select_export(sql_exchange *ex) :select_to_file(ex) {} + select_export(THD *thd_arg, sql_exchange *ex): select_to_file(thd_arg, ex) {} ~select_export(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int send_data(List<Item> &items); @@ -4089,7 +4468,7 @@ public: class select_dump :public select_to_file { public: - select_dump(sql_exchange *ex) :select_to_file(ex) {} + select_dump(THD *thd_arg, sql_exchange *ex): select_to_file(thd_arg, ex) {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int send_data(List<Item> &items); }; @@ -4103,7 +4482,7 @@ class select_insert :public select_result_interceptor { ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not COPY_INFO info; bool insert_into_view; - select_insert(TABLE_LIST *table_list_par, + select_insert(THD *thd_arg, TABLE_LIST *table_list_par, TABLE *table_par, List<Item> *fields_par, List<Item> *update_fields, List<Item> *update_values, enum_duplicates duplic, bool ignore); @@ -4113,6 +4492,8 @@ 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; } + bool prepare_eof(); + bool send_ok_packet(); bool send_eof(); virtual void abort_result_set(); /* not implemented: select_insert is never re-used in prepared statements */ @@ -4123,7 +4504,7 @@ class select_insert :public select_result_interceptor { class select_create: public select_insert { ORDER *group; TABLE_LIST *create_table; - HA_CREATE_INFO *create_info; + Table_specification_st *create_info; TABLE_LIST *select_tables; Alter_info *alter_info; Field **field; @@ -4134,12 +4515,12 @@ class select_create: public select_insert { bool exit_done; public: - select_create (TABLE_LIST *table_arg, - HA_CREATE_INFO *create_info_par, - Alter_info *alter_info_arg, - List<Item> &select_fields,enum_duplicates duplic, bool ignore, - TABLE_LIST *select_tables_arg) - :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), + select_create(THD *thd_arg, TABLE_LIST *table_arg, + Table_specification_st *create_info_par, + Alter_info *alter_info_arg, + List<Item> &select_fields,enum_duplicates duplic, bool ignore, + TABLE_LIST *select_tables_arg): + select_insert(thd_arg, NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table_arg), create_info(create_info_par), select_tables(select_tables_arg), @@ -4235,8 +4616,6 @@ public: uint group_parts,group_length,group_null_parts; uint quick_group; bool using_indirect_summary_function; - /* If >0 convert all blob fields to varchar(convert_blob_length) */ - uint convert_blob_length; CHARSET_INFO *table_charset; bool schema_table; /* TRUE if the temp table is created for subquery materialization. */ @@ -4265,7 +4644,7 @@ public: TMP_TABLE_PARAM() :copy_field(0), group_parts(0), - group_length(0), group_null_parts(0), convert_blob_length(0), + group_length(0), group_null_parts(0), schema_table(0), materialized_subquery(0), force_not_null_cols(0), precomputed_group_by(0), force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0) @@ -4300,11 +4679,23 @@ public: TABLE *table; ha_rows records; - select_union() :write_err(0), table(0), records(0) { tmp_table_param.init(); } + select_union(THD *thd_arg): + select_result_interceptor(thd_arg), write_err(0), table(0), records(0) + { tmp_table_param.init(); } int prepare(List<Item> &list, SELECT_LEX_UNIT *u); + /** + Do prepare() and prepare2() if they have been postponed until + column type information is computed (used by select_union_direct). + + @param types Column types + + @return false on success, true on failure + */ + virtual bool postponed_prepare(List<Item> &types) + { return false; } int send_data(List<Item> &items); bool send_eof(); - bool flush(); + virtual bool flush(); void cleanup(); virtual bool create_result_table(THD *thd, List<Item> *column_types, bool is_distinct, ulonglong options, @@ -4315,13 +4706,108 @@ public: TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; } }; + +/** + UNION result that is passed directly to the receiving select_result + without filling a temporary table. + + Function calls are forwarded to the wrapped select_result, but some + functions are expected to be called only once for each query, so + they are only executed for the first SELECT in the union (execept + for send_eof(), which is executed only for the last SELECT). + + This select_result is used when a UNION is not DISTINCT and doesn't + have a global ORDER BY clause. @see st_select_lex_unit::prepare(). +*/ + +class select_union_direct :public select_union +{ +private: + /* Result object that receives all rows */ + select_result *result; + /* The last SELECT_LEX of the union */ + SELECT_LEX *last_select_lex; + + /* Wrapped result has received metadata */ + bool done_send_result_set_metadata; + /* Wrapped result has initialized tables */ + bool done_initialize_tables; + + /* Accumulated limit_found_rows */ + ulonglong limit_found_rows; + + /* Number of rows offset */ + ha_rows offset; + /* Number of rows limit + offset, @see select_union_direct::send_data() */ + ha_rows limit; + +public: + /* Number of rows in the union */ + ha_rows send_records; + select_union_direct(THD *thd_arg, select_result *result_arg, + SELECT_LEX *last_select_lex_arg): + select_union(thd_arg), result(result_arg), + last_select_lex(last_select_lex_arg), + done_send_result_set_metadata(false), done_initialize_tables(false), + limit_found_rows(0) + { send_records= 0; } + bool change_result(select_result *new_result); + uint field_count(List<Item> &fields) const + { + // Only called for top-level select_results, usually select_send + DBUG_ASSERT(false); /* purecov: inspected */ + return 0; /* purecov: inspected */ + } + bool postponed_prepare(List<Item> &types); + bool send_result_set_metadata(List<Item> &list, uint flags); + int send_data(List<Item> &items); + bool initialize_tables (JOIN *join= NULL); + bool send_eof(); + bool flush() { return false; } + bool check_simple_select() const + { + /* Only called for top-level select_results, usually select_send */ + DBUG_ASSERT(false); /* purecov: inspected */ + return false; /* purecov: inspected */ + } + void abort_result_set() + { + result->abort_result_set(); /* purecov: inspected */ + } + void cleanup() + { + send_records= 0; + } + void set_thd(THD *thd_arg) + { + /* + Only called for top-level select_results, usually select_send, + and for the results of subquery engines + (select_<something>_subselect). + */ + DBUG_ASSERT(false); /* purecov: inspected */ + } + void reset_offset_limit_cnt() + { + // EXPLAIN should never output to a select_union_direct + DBUG_ASSERT(false); /* purecov: inspected */ + } + void begin_dataset() + { + // Only called for sp_cursor::Select_fetch_into_spvars + DBUG_ASSERT(false); /* purecov: inspected */ + } +}; + + /* Base subselect interface class */ class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: - select_subselect(Item_subselect *item); + select_subselect(THD *thd_arg, Item_subselect *item_arg): + select_result_interceptor(thd_arg), item(item_arg) {} int send_data(List<Item> &items)=0; bool send_eof() { return 0; }; }; @@ -4330,8 +4816,8 @@ public: class select_singlerow_subselect :public select_subselect { public: - select_singlerow_subselect(Item_subselect *item_arg) - :select_subselect(item_arg) + select_singlerow_subselect(THD *thd_arg, Item_subselect *item_arg): + select_subselect(thd_arg, item_arg) {} int send_data(List<Item> &items); }; @@ -4376,7 +4862,8 @@ protected: void reset(); public: - select_materialize_with_stats() { tmp_table_param.init(); } + select_materialize_with_stats(THD *thd_arg): select_union(thd_arg) + { tmp_table_param.init(); } bool create_result_table(THD *thd, List<Item> *column_types, bool is_distinct, ulonglong options, const char *alias, @@ -4413,9 +4900,9 @@ class select_max_min_finder_subselect :public select_subselect bool fmax; bool is_all; public: - select_max_min_finder_subselect(Item_subselect *item_arg, bool mx, - bool all) - :select_subselect(item_arg), cache(0), fmax(mx), is_all(all) + select_max_min_finder_subselect(THD *thd_arg, Item_subselect *item_arg, + bool mx, bool all): + select_subselect(thd_arg, item_arg), cache(0), fmax(mx), is_all(all) {} void cleanup(); int send_data(List<Item> &items); @@ -4429,8 +4916,8 @@ public: class select_exists_subselect :public select_subselect { public: - select_exists_subselect(Item_subselect *item_arg) - :select_subselect(item_arg){} + select_exists_subselect(THD *thd_arg, Item_subselect *item_arg): + select_subselect(thd_arg, item_arg) {} int send_data(List<Item> &items); }; @@ -4562,6 +5049,7 @@ public: // this is needed for user_vars hash class user_var_entry { + CHARSET_INFO *m_charset; public: user_var_entry() {} /* Remove gcc warning */ LEX_STRING name; @@ -4575,7 +5063,8 @@ class user_var_entry longlong val_int(bool *null_value) const; String *val_str(bool *null_value, String *str, uint decimals); my_decimal *val_decimal(bool *null_value, my_decimal *result); - DTCollation collation; + CHARSET_INFO *charset() const { return m_charset; } + void set_charset(CHARSET_INFO *cs) { m_charset= cs; } }; user_var_entry *get_variable(HASH *hash, LEX_STRING &name, @@ -4681,7 +5170,7 @@ class multi_delete :public select_result_interceptor bool error_handled; public: - multi_delete(TABLE_LIST *dt, uint num_of_tables); + multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int send_data(List<Item> &items); @@ -4728,7 +5217,7 @@ class multi_update :public select_result_interceptor /* Need this to protect against multiple prepare() calls */ bool prepared; public: - multi_update(TABLE_LIST *ut, List<TABLE_LIST> *leaves_list, + multi_update(THD *thd_arg, TABLE_LIST *ut, List<TABLE_LIST> *leaves_list, List<Item> *fields, List<Item> *values, enum_duplicates handle_duplicates, bool ignore); ~multi_update(); @@ -4751,28 +5240,43 @@ public: class my_var : public Sql_alloc { public: - LEX_STRING s; -#ifndef DBUG_OFF + const LEX_STRING name; + enum type { SESSION_VAR, LOCAL_VAR, PARAM_VAR }; + type scope; + my_var(const LEX_STRING& j, enum type s) : name(j), scope(s) { } + virtual ~my_var() {} + virtual bool set(THD *thd, Item *val) = 0; +}; + +class my_var_sp: public my_var { +public: + uint offset; + enum_field_types type; /* Routine to which this Item_splocal belongs. Used for checking if correct runtime context is used for variable handling. */ sp_head *sp; -#endif - bool local; - uint offset; - enum_field_types type; - my_var (LEX_STRING& j, bool i, uint o, enum_field_types t) - :s(j), local(i), offset(o), type(t) - {} - ~my_var() {} + my_var_sp(const LEX_STRING& j, uint o, enum_field_types t, sp_head *s) + : my_var(j, LOCAL_VAR), offset(o), type(t), sp(s) { } + ~my_var_sp() { } + bool set(THD *thd, Item *val); +}; + +class my_var_user: public my_var { +public: + my_var_user(const LEX_STRING& j) + : my_var(j, SESSION_VAR) { } + ~my_var_user() { } + bool set(THD *thd, Item *val); }; class select_dumpvar :public select_result_interceptor { ha_rows row_count; public: List<my_var> var_list; - select_dumpvar() { var_list.empty(); row_count= 0;} + select_dumpvar(THD *thd_arg): select_result_interceptor(thd_arg) + { var_list.empty(); row_count= 0; } ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int send_data(List<Item> &items); @@ -4908,6 +5412,11 @@ public: */ #define CF_SKIP_QUESTIONS (1U << 1) +/** + Do not check that wsrep snapshot is ready before allowing this command +*/ +#define CF_SKIP_WSREP_CHECK (1U << 2) + /* Inline functions */ inline bool add_item_to_list(THD *thd, Item *item) @@ -4917,7 +5426,7 @@ inline bool add_item_to_list(THD *thd, Item *item) inline bool add_value_to_list(THD *thd, Item *value) { - return thd->lex->value_list.push_back(value); + return thd->lex->value_list.push_back(value, thd->mem_root); } inline bool add_order_to_list(THD *thd, Item *item, bool asc) @@ -4935,6 +5444,13 @@ inline bool add_group_to_list(THD *thd, Item *item, bool asc) return thd->lex->current_select->add_group_to_list(thd, item, asc); } +inline Item *and_conds(THD *thd, Item *a, Item *b) +{ + if (!b) return a; + if (!a) return b; + return new (thd->mem_root) Item_cond_and(thd, a, b); +} + /* inline handler methods that need to know TABLE and THD structures */ inline void handler::increment_statistics(ulong SSV::*offset) const { @@ -4981,8 +5497,8 @@ inline int handler::ha_write_tmp_row(uchar *buf) int error; MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_write_count); - MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, - { error= write_row(buf); }) + TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, + { error= write_row(buf); }) MYSQL_INSERT_ROW_DONE(error); return error; } @@ -4992,12 +5508,13 @@ 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); - MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, - { error= update_row(old_data, new_data);}) + TABLE_IO_WAIT(tracker, 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); /** |