diff options
author | unknown <serg@janus.mylan> | 2007-02-26 16:12:40 +0100 |
---|---|---|
committer | unknown <serg@janus.mylan> | 2007-02-26 16:12:40 +0100 |
commit | 39622e126775b6b7de3b727aa4dd0da5fdab5d74 (patch) | |
tree | abec5b528446805866d0c3e28ebea8ef58ccab4f /sql | |
parent | 506af377b3af4b677fce194e0935aca4cd230a5a (diff) | |
parent | 1eb71c68cb1b2f335a8e6b393cdb3e724ea65a0a (diff) | |
download | mariadb-git-39622e126775b6b7de3b727aa4dd0da5fdab5d74.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into janus.mylan:/usr/home/serg/Abk/mysql-5.1
include/my_global.h:
Auto merged
sql/ha_ndbcluster.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/log.cc:
Auto merged
sql/log_event.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/opt_range.cc:
Auto merged
sql/opt_range.h:
Auto merged
sql/slave.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/table.cc:
Auto merged
sql/tztime.cc:
Auto merged
storage/innobase/handler/ha_innodb.cc:
Auto merged
storage/myisam/ha_myisam.cc:
Auto merged
storage/myisammrg/ha_myisammrg.cc:
Auto merged
support-files/Makefile.am:
Auto merged
BUILD/compile-solaris-sparc-forte:
merged
BUILD/compile-solaris-sparc-purify:
merged
Diffstat (limited to 'sql')
48 files changed, 1704 insertions, 1489 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 37707fe3963..002aabb91b0 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -69,6 +69,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc sql_tablespace.cc events.cc ../sql-common/my_user.c partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc rpl_rli.cc rpl_mi.cc sql_servers.cc + sql_connect.cc scheduler.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 43331e3d0c9..c3a692615dd 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -64,10 +64,11 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ - sql_array.h sql_cursor.h events.h \ + sql_array.h sql_cursor.h events.h scheduler.h \ event_db_repository.h event_queue.h \ - sql_plugin.h authors.h sql_partition.h event_data_objects.h \ - partition_info.h partition_element.h event_scheduler.h \ + sql_plugin.h authors.h \ + event_data_objects.h event_scheduler.h \ + sql_partition.h partition_info.h partition_element.h \ contributors.h sql_servers.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -79,7 +80,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ - set_var.cc sql_parse.cc sql_yacc.yy \ + sql_connect.cc scheduler.cc sql_parse.cc \ + set_var.cc sql_yacc.yy \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ sql_prepare.cc sql_error.cc sql_locale.cc \ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \ diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index a47576cf0c0..aeacaef0b6d 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -104,25 +104,22 @@ evex_print_warnings(THD *thd, Event_job_data *et) SYNOPSIS post_init_event_thread() thd Thread + + NOTES + Before this is called, one should not do any DBUG_XXX() calls. + */ bool post_init_event_thread(THD *thd) { - my_thread_init(); - pthread_detach_this_thread(); - thd->real_id= pthread_self(); + (void) init_new_connection_handler_thread(); if (init_thr_lock() || thd->store_globals()) { thd->cleanup(); return TRUE; } -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); thread_count++; @@ -187,7 +184,7 @@ pre_init_event_thread(THD* thd) thd->options|= OPTION_AUTO_IS_NULL; thd->client_capabilities|= CLIENT_MULTI_RESULTS; pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id= thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); /* @@ -218,20 +215,20 @@ pthread_handler_t event_scheduler_thread(void *arg) { /* needs to be first for thread_stack */ - THD *thd= (THD *)((struct scheduler_param *) arg)->thd; + THD *thd= (THD *) ((struct scheduler_param *) arg)->thd; Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler; + bool res; - my_free((char*)arg, MYF(0)); - - thd->thread_stack= (char *)&thd; // remember where our stack is + thd->thread_stack= (char*) &thd; // remember where our stack is + res= post_init_event_thread(thd); DBUG_ENTER("event_scheduler_thread"); - - if (!post_init_event_thread(thd)) + my_free((char*)arg, MYF(0)); + if (!res) scheduler->run(thd); deinit_event_thread(thd); - + pthread_exit(0); DBUG_RETURN(0); // Against gcc warnings } @@ -255,13 +252,14 @@ event_worker_thread(void *arg) THD *thd; Event_job_data *event= (Event_job_data *)arg; int ret; + bool res; thd= event->thd; - thd->thread_stack= (char *) &thd; // remember where our stack is + res= post_init_event_thread(thd); DBUG_ENTER("event_worker_thread"); - if (!post_init_event_thread(thd)) + if (!res) { DBUG_PRINT("info", ("Baikonur, time is %ld, BURAN reporting and operational." "THD: 0x%lx", @@ -295,6 +293,7 @@ event_worker_thread(void *arg) deinit_event_thread(thd); + pthread_exit(0); DBUG_RETURN(0); // Can't return anything here } diff --git a/sql/field.h b/sql/field.h index cd897cc32b3..f27ed8b9394 100644 --- a/sql/field.h +++ b/sql/field.h @@ -825,8 +825,8 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(double); } void sql_type(String &str) const; - uint size_of() const { return sizeof(*this); } uint32 max_display_length() { return 53; } + uint size_of() const { return sizeof(*this); } }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index bedce2f1ca6..6766e9b990a 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2820,7 +2820,7 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row, int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) { - THD *thd= current_thd; + THD *thd= table->in_use; NdbTransaction *trans= m_active_trans; NdbScanOperation* cursor= m_active_cursor; NdbOperation *op; @@ -3007,7 +3007,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) int ha_ndbcluster::delete_row(const byte *record) { - THD *thd= current_thd; + THD *thd= table->in_use; NdbTransaction *trans= m_active_trans; NdbScanOperation* cursor= m_active_cursor; NdbOperation *op; @@ -6003,7 +6003,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { DBUG_ENTER("close"); - THD *thd= current_thd; + THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; /* ndb_share reference handler free */ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u", diff --git a/sql/handler.cc b/sql/handler.cc index 2f458cdb0ba..74ea2b91eda 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -845,7 +845,7 @@ int ha_rollback_trans(THD *thd, bool all) message in the error log, so we don't send it. */ if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && - !thd->slave_thread) + !thd->slave_thread && thd->killed != THD::KILL_CONNECTION) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); @@ -2856,8 +2856,8 @@ ha_find_files(THD *thd,const char *db,const char *path, { int error= 0; DBUG_ENTER("ha_find_files"); - DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d", - db, path, wild, dir)); + DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d", + db, path, wild ? wild : "NULL", dir)); st_find_files_args args= {db, path, wild, dir, files}; plugin_foreach(thd, find_files_handlerton, diff --git a/sql/item.cc b/sql/item.cc index 48ca03ada0a..d0691979c66 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1553,6 +1553,8 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, doesn't display each argument's characteristics. - if nargs is 1, then this error cannot happen. */ + LINT_INIT(safe_args[0]); + LINT_INIT(safe_args[1]); if (nargs >=2 && nargs <= 3) { safe_args[0]= args[0]; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86a47c35e0a..17da1174e37 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -903,6 +903,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) longlong Item_in_optimizer::val_int() { + bool tmp; DBUG_ASSERT(fixed == 1); cache->store(args[0]); @@ -966,7 +967,7 @@ longlong Item_in_optimizer::val_int() } return 0; } - bool tmp= args[1]->val_bool_result(); + tmp= args[1]->val_bool_result(); null_value= args[1]->null_value; return tmp; } diff --git a/sql/item_func.cc b/sql/item_func.cc index cd0229e0548..aa344a343de 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3087,14 +3087,8 @@ public: int count; bool locked; pthread_cond_t cond; -#ifndef EMBEDDED_LIBRARY - pthread_t thread; - void set_thread(THD *thd) { thread= thd->real_id; } -#else - THD *thread; - void set_thread(THD *thd) { thread= thd; } -#endif /*EMBEDDED_LIBRARY*/ - ulong thread_id; + my_thread_id thread_id; + void set_thread(THD *thd) { thread_id= thd->thread_id; } User_level_lock(const char *key_arg,uint length, ulong id) :key_length(length),count(1),locked(1), thread_id(id) @@ -3411,11 +3405,7 @@ longlong Item_func_release_lock::val_int() } else { -#ifdef EMBEDDED_LIBRARY - if (ull->locked && (current_thd == ull->thread)) -#else - if (ull->locked && pthread_equal(pthread_self(),ull->thread)) -#endif + if (ull->locked && current_thd->thread_id == ull->thread_id) { result=1; // Release is ok item_user_lock_release(ull); @@ -3460,7 +3450,7 @@ longlong Item_func_benchmark::val_int() THD *thd=current_thd; ulong loop_count; - loop_count= args[0]->val_int(); + loop_count= (ulong) args[0]->val_int(); if (args[0]->null_value) { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index faea5380a66..acc522b1b46 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -25,9 +25,6 @@ #include "mysql_priv.h" #include <m_ctype.h> -#ifdef HAVE_OPENSSL -#include <openssl/des.h> -#endif /* HAVE_OPENSSL */ #include "md5.h" #include "sha1.h" #include "my_aes.h" @@ -1926,7 +1923,7 @@ String *Item_func_format::val_str(String *str) int diff; DBUG_ASSERT(fixed == 1); - dec= args[1]->val_int(); + dec= (int) args[1]->val_int(); if (args[1]->null_value) { null_value=1; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 00f077839c3..1bf1fec5cfb 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1587,7 +1587,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time) { THD *thd= current_thd; - thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL)); + thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL)); thd->time_zone_used= 1; } diff --git a/sql/lex.h b/sql/lex.h index 2bf0e08c825..45155da7692 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -222,7 +222,7 @@ static SYMBOL symbols[] = { { "GLOBAL", SYM(GLOBAL_SYM)}, { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, - { "GROUP", SYM(GROUP)}, + { "GROUP", SYM(GROUP_SYM)}, { "HANDLER", SYM(HANDLER_SYM)}, { "HASH", SYM(HASH_SYM)}, { "HAVING", SYM(HAVING)}, diff --git a/sql/lock.cc b/sql/lock.cc index 533307c6b85..edef3b3b67f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -485,7 +485,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) for (uint i=0; i < locked->lock_count; i++) { if (thr_abort_locks_for_thread(locked->locks[i]->lock, - table->in_use->real_id)) + table->in_use->thread_id)) result= TRUE; } my_free((gptr) locked,MYF(0)); diff --git a/sql/log.cc b/sql/log.cc index f20ae13e49a..6e24a0b99ea 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -267,7 +267,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type) table->table_name_length= 8; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } /* @@ -1161,7 +1161,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type) log_thd= table_log_handler->general_log_thd; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } if (!(*tmp_opt)) @@ -1310,7 +1310,7 @@ void Log_to_csv_event_handler:: table= &slow_log; break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } /* @@ -3887,7 +3887,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) #ifdef HAVE_REPLICATION if (expire_logs_days) { - long purge_time= time(0) - expire_logs_days*24*60*60; + long purge_time= (long) (time(0) - expire_logs_days*24*60*60); if (purge_time >= 0) purge_logs_before_date(purge_time); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 02dc53e6ebc..23ac1e10062 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1148,7 +1148,6 @@ void Log_event::print_base64(IO_CACHE* file, { const uchar *ptr= (const uchar *)temp_buf; uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET); - DBUG_ENTER("Log_event::print_base64"); size_t const tmp_str_sz= base64_needed_encoded_length((int) size); @@ -1159,8 +1158,10 @@ void Log_event::print_base64(IO_CACHE* file, DBUG_VOID_RETURN; } - int const res= base64_encode(ptr, (size_t) size, tmp_str); - DBUG_ASSERT(res == 0); + if (base64_encode(ptr, (size_t) size, tmp_str)) + { + DBUG_ASSERT(0); + } if (my_b_tell(file) == 0) my_b_printf(file, "\nBINLOG '\n"); @@ -5471,7 +5472,7 @@ int Rows_log_event::do_add_row_data(byte *const row_data, my_ptrdiff_t const new_alloc= block_size * ((cur_size + length) / block_size + block_size - 1); - byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, new_alloc, + byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, (uint) new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME)); if (unlikely(!new_buf)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -6014,7 +6015,7 @@ bool Rows_log_event::write_data_body(IO_CACHE*file) sbuf_end - sbuf) || my_b_safe_write(file, reinterpret_cast<byte*>(m_cols.bitmap), no_bytes_in_map(&m_cols)) || - my_b_safe_write(file, m_rows_buf, data_size)); + my_b_safe_write(file, m_rows_buf, (uint) data_size)); } #endif @@ -6367,8 +6368,8 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file) DBUG_ASSERT(m_dblen < 128); DBUG_ASSERT(m_tbllen < 128); - byte const dbuf[]= { m_dblen }; - byte const tbuf[]= { m_tbllen }; + byte const dbuf[]= { (byte) m_dblen }; + byte const tbuf[]= { (byte) m_tbllen }; char cbuf[sizeof(m_colcnt)]; char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d8c94e3dc4e..e3815c2b235 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -38,6 +38,7 @@ #include <queues.h> #include "sql_bitmap.h" #include "sql_array.h" +#include "scheduler.h" /* TODO convert all these three maps to Bitmap classes */ typedef ulonglong table_map; /* Used for table bits in join */ @@ -282,7 +283,6 @@ MY_LOCALE *my_locale_by_number(uint number); #define TEST_MIT_THREAD 4 #define TEST_BLOCKING 8 #define TEST_KEEP_TMP_TABLES 16 -#define TEST_NO_THREADS 32 /* For debugging under Linux */ #define TEST_READCHECK 64 /* Force use of readcheck */ #define TEST_NO_EXTRA 128 #define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */ @@ -787,6 +787,23 @@ uint build_table_path(char *buff, size_t bufflen, const char *db, void write_bin_log(THD *thd, bool clear_error, char const *query, ulong query_length); +/* sql_connect.cc */ +int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count); +pthread_handler_t handle_one_connection(void *arg); +bool init_new_connection_handler_thread(); +void reset_mqh(LEX_USER *lu, bool get_them); +bool check_mqh(THD *thd, uint check_command); +void time_out_user_resource_limits(THD *thd, USER_CONN *uc); +int check_for_max_user_connections(THD *thd, USER_CONN *uc); +void decrease_user_connections(USER_CONN *uc); +void thd_init_client_charset(THD *thd, uint cs_number); +bool setup_connection_thread_globals(THD *thd); +bool login_connection(THD *thd); +void prepare_new_connection_state(THD* thd); +void end_connection(THD *thd); + bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); @@ -822,10 +839,7 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); -pthread_handler_t handle_one_connection(void *arg); pthread_handler_t handle_bootstrap(void *arg); -void end_thread(THD *thd,bool put_in_cache); -void flush_thread_cache(); bool mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, @@ -1495,6 +1509,11 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, extern void MYSQLerror(const char*); void refresh_status(THD *thd); my_bool mysql_rm_tmp_tables(void); +void handle_connection_in_main_thread(THD *thd); +void create_thread_to_handle_connection(THD *thd); +void unlink_thd(THD *thd); +bool one_thread_per_connection_end(THD *thd, bool put_in_cache); +void flush_thread_cache(); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); @@ -1578,7 +1597,7 @@ extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; extern ulong opt_binlog_rows_event_max_size; -extern ulong rpl_recovery_rank, thread_cache_size; +extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size; extern ulong back_log; extern ulong specialflag, current_pid; extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter; @@ -1663,6 +1682,9 @@ extern TABLE *unused_tables; extern const char* any_db; extern struct my_option my_long_options[]; extern const LEX_STRING view_type; +extern scheduler_functions thread_scheduler; +extern TYPELIB thread_handling_typelib; +extern uint8 uc_update_queries[SQLCOM_END+1]; extern uint sql_command_flags[]; extern TYPELIB log_output_typelib; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 172891b7c8e..a6525c1c78c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -59,10 +59,6 @@ #define mysqld_charset &my_charset_latin1 -#ifndef DBUG_OFF -#define ONE_THREAD -#endif - #ifdef HAVE_purify #define IF_PURIFY(A,B) (A) #else @@ -282,6 +278,16 @@ static TYPELIB tc_heuristic_recover_typelib= array_elements(tc_heuristic_recover_names)-1,"", tc_heuristic_recover_names, NULL }; + +static const char *thread_handling_names[]= +{ "one-thread-per-connection", "no-threads", "pool-of-threads", NullS}; + +TYPELIB thread_handling_typelib= +{ + array_elements(thread_handling_names) - 1, "", + thread_handling_names, NULL +}; + const char *first_keyword= "first", *binary_keyword= "BINARY"; const char *my_localhost= "localhost", *delayed_user= "DELAYED"; #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) @@ -467,7 +473,8 @@ ulong thread_stack, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; -ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; +ulong thread_cache_size=0, thread_pool_size= 0; +ulong binlog_cache_size=0, max_binlog_cache_size=0; ulong query_cache_size=0; ulong refresh_version, flush_version; /* Increments on each reload */ query_id_t global_query_id; @@ -681,6 +688,8 @@ my_bool opt_enable_shared_memory; HANDLE smem_event_connect_request= 0; #endif +scheduler_functions thread_scheduler; + #define SSL_VARS_NOT_STATIC #include "sslopt-vars.h" #ifdef HAVE_OPENSSL @@ -861,6 +870,7 @@ static void close_connections(void) continue; tmp->killed= THD::KILL_CONNECTION; + thread_scheduler.post_kill_notification(tmp); if (tmp->mysys_var) { tmp->mysys_var->abort=1; @@ -1254,6 +1264,7 @@ void clean_up(bool print_message) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif + thread_scheduler.end(); finish_client_errs(); my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST), MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); @@ -1513,6 +1524,9 @@ static void network_init(void) DBUG_ENTER("network_init"); LINT_INIT(ret); + if (thread_scheduler.init()) + unireg_abort(1); /* purecov: inspected */ + set_ports(); if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap) @@ -1731,21 +1745,55 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused))) if (thd && ! thd->bootstrap) { statistic_increment(killed_threads, &LOCK_status); - end_thread(thd,0); + thread_scheduler.end_thread(thd,0); /* purecov: inspected */ } DBUG_VOID_RETURN; /* purecov: deadcode */ } -void end_thread(THD *thd, bool put_in_cache) +/* + Unlink thd from global list of available connections and free thd + + SYNOPSIS + unlink_thd() + thd Thread handler + + NOTES + LOCK_thread_count is locked and left locked +*/ + +void unlink_thd(THD *thd) { - DBUG_ENTER("end_thread"); + DBUG_ENTER("unlink_thd"); + DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); thd->cleanup(); (void) pthread_mutex_lock(&LOCK_thread_count); thread_count--; delete thd; + DBUG_VOID_RETURN; +} + - if (put_in_cache && cached_thread_count < thread_cache_size && +/* + Store thread in cache for reuse by new connections + + SYNOPSIS + cache_thread() + + NOTES + LOCK_thread_count has to be locked + + RETURN + 0 Thread was not put in cache + 1 Thread is to be reused by new connection. + (ie, caller should return, not abort with pthread_exit()) +*/ + + +static bool cache_thread() +{ + safe_mutex_assert_owner(&LOCK_thread_count); + if (cached_thread_count < thread_cache_size && ! abort_loop && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ @@ -1758,31 +1806,56 @@ void end_thread(THD *thd, bool put_in_cache) pthread_cond_signal(&COND_flush_thread_cache); if (wake_thread) { + THD *thd; wake_thread--; - thd=thread_cache.get(); - thd->real_id=pthread_self(); + thd= thread_cache.get(); thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); thd->thr_create_time= time(NULL); threads.append(thd); - pthread_mutex_unlock(&LOCK_thread_count); - DBUG_VOID_RETURN; + return(1); } } + return(0); +} + + +/* + End thread for the current connection + + SYNOPSIS + one_thread_per_connection_end() + thd Thread handler + put_in_cache Store thread in cache, if there is room in it + Normally this is true in all cases except when we got + out of resources initializing the current thread + + NOTES + If thread is cached, we will wait until thread is scheduled to be + reused and then we will return. + If thread is not cached, we end the thread. + + RETURN + 0 Signal to handle_one_connection to reuse connection +*/ + +bool one_thread_per_connection_end(THD *thd, bool put_in_cache) +{ + DBUG_ENTER("one_thread_per_connection_end"); + unlink_thd(thd); + if (put_in_cache) + put_in_cache= cache_thread(); + pthread_mutex_unlock(&LOCK_thread_count); + if (put_in_cache) + DBUG_RETURN(0); // Thread is reused - /* Tell main we are ready */ - (void) pthread_mutex_unlock(&LOCK_thread_count); /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); (void) pthread_cond_broadcast(&COND_thread_count); -#ifdef ONE_THREAD - if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux -#endif - { - my_thread_end(); - pthread_exit(0); - } - DBUG_VOID_RETURN; + + my_thread_end(); + pthread_exit(0); + DBUG_RETURN(0); // Impossible } @@ -2123,14 +2196,15 @@ and this may fail.\n\n"); (ulong) dflt_key_cache->key_cache_mem_size); fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size); fprintf(stderr, "max_used_connections=%lu\n", max_used_connections); - fprintf(stderr, "max_connections=%lu\n", max_connections); + fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads); fprintf(stderr, "threads_connected=%u\n", thread_count); fprintf(stderr, "It is possible that mysqld could use up to \n\ -key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\ +key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\ bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size + (global_system_variables.read_buff_size + global_system_variables.sortbuff_size) * - max_connections)/ 1024); + thread_scheduler.max_threads + + max_connections * sizeof(THD)) / 1024); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); #if defined(HAVE_LINUXTHREADS) @@ -2331,7 +2405,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) This should actually be '+ max_number_of_slaves' instead of +10, but the +10 should be quite safe. */ - init_thr_alarm(max_connections + + init_thr_alarm(thread_scheduler.max_threads + global_system_variables.max_insert_delayed_threads + 10); #if SIGINT != THR_KILL_SIGNAL if (test_flags & TEST_SIGINT) @@ -2535,18 +2609,6 @@ static void my_str_free_mysqld(void *ptr) #ifdef __WIN__ -struct utsname -{ - char nodename[FN_REFLEN]; -}; - - -int uname(struct utsname *a) -{ - return -1; -} - - pthread_handler_t handle_shutdown(void *arg) { MSG msg; @@ -3357,7 +3419,7 @@ server."); #ifdef HAVE_REPLICATION if (opt_bin_log && expire_logs_days) { - long purge_time= time(0) - expire_logs_days*24*60*60; + long purge_time= (long) (time(0) - expire_logs_days*24*60*60); if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } @@ -4009,7 +4071,7 @@ static void bootstrap(FILE *file) my_net_init(&thd->net,(st_vio*) 0); thd->max_client_packet_length= thd->net.max_packet; thd->security_ctx->master_access= ~(ulong)0; - thd->thread_id=thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; thread_count++; bootstrap_file=file; @@ -4052,6 +4114,74 @@ static bool read_init_file(char *file_name) #ifndef EMBEDDED_LIBRARY + +/* + Simple scheduler that use the main thread to handle the request + + NOTES + This is only used for debugging, when starting mysqld with + --thread-handling=no-threads or --one-thread + + When we enter this function, LOCK_thread_count is hold! +*/ + +void handle_connection_in_main_thread(THD *thd) +{ + safe_mutex_assert_owner(&LOCK_thread_count); + thread_cache_size=0; // Safety + threads.append(thd); + (void) pthread_mutex_unlock(&LOCK_thread_count); + handle_one_connection((void*) thd); +} + + +/* + Scheduler that uses one thread per connection +*/ + +void create_thread_to_handle_connection(THD *thd) +{ + if (cached_thread_count > wake_thread) + { + /* Get thread from cache */ + thread_cache.append(thd); + wake_thread++; + pthread_cond_signal(&COND_thread_cache); + } + else + { + /* Create new thread to handle connection */ + int error; + thread_created++; + threads.append(thd); + DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); + thd->connect_time = time(NULL); + if ((error=pthread_create(&thd->real_id,&connection_attrib, + handle_one_connection, + (void*) thd))) + { + /* purify: begin inspected */ + DBUG_PRINT("error", + ("Can't create thread to handle request (error %d)", + error)); + thread_count--; + thd->killed= THD::KILL_CONNECTION; // Safety + (void) pthread_mutex_unlock(&LOCK_thread_count); + statistic_increment(aborted_connects,&LOCK_status); + net_printf_error(thd, ER_CANT_CREATE_THREAD, error); + (void) pthread_mutex_lock(&LOCK_thread_count); + close_connection(thd,0,0); + delete thd; + (void) pthread_mutex_unlock(&LOCK_thread_count); + return; + /* purecov: end */ + } + } + (void) pthread_mutex_unlock(&LOCK_thread_count); + DBUG_PRINT("info",("Thread created")); +} + + /* Create new thread to handle incoming connection. @@ -4088,64 +4218,15 @@ static void create_new_thread(THD *thd) DBUG_VOID_RETURN; } pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; - - thd->real_id=pthread_self(); // Keep purify happy + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; /* Start a new thread to handle connection */ thread_count++; -#ifdef ONE_THREAD - if (test_flags & TEST_NO_THREADS) // For debugging under Linux - { - thread_cache_size=0; // Safety - threads.append(thd); - thd->real_id=pthread_self(); - (void) pthread_mutex_unlock(&LOCK_thread_count); - handle_one_connection((void*) thd); - } - else -#endif - { - if (thread_count-delayed_insert_threads > max_used_connections) - max_used_connections=thread_count-delayed_insert_threads; + if (thread_count - delayed_insert_threads > max_used_connections) + max_used_connections= thread_count - delayed_insert_threads; - if (cached_thread_count > wake_thread) - { - thread_cache.append(thd); - wake_thread++; - pthread_cond_signal(&COND_thread_cache); - } - else - { - int error; - thread_created++; - threads.append(thd); - DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->connect_time = time(NULL); - if ((error=pthread_create(&thd->real_id,&connection_attrib, - handle_one_connection, - (void*) thd))) - { - DBUG_PRINT("error", - ("Can't create thread to handle request (error %d)", - error)); - thread_count--; - thd->killed= THD::KILL_CONNECTION; // Safety - (void) pthread_mutex_unlock(&LOCK_thread_count); - statistic_increment(aborted_connects,&LOCK_status); - net_printf_error(thd, ER_CANT_CREATE_THREAD, error); - (void) pthread_mutex_lock(&LOCK_thread_count); - close_connection(thd,0,0); - delete thd; - (void) pthread_mutex_unlock(&LOCK_thread_count); - DBUG_VOID_RETURN; - } - } - (void) pthread_mutex_unlock(&LOCK_thread_count); - - } - DBUG_PRINT("info",("Thread created")); + thread_scheduler.add_connection(thd); DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ @@ -4895,6 +4976,7 @@ enum options_mysqld OPT_GENERAL_LOG, OPT_SLOW_LOG, OPT_MERGE, + OPT_THREAD_HANDLING, OPT_INNODB_ROLLBACK_ON_TIMEOUT }; @@ -5502,11 +5584,9 @@ Disable with --skip-ndbcluster (will save memory).", (gptr*) &global_system_variables.old_passwords, (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef ONE_THREAD {"one-thread", OPT_ONE_THREAD, - "Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif + "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS, "Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)", (gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits, @@ -5985,7 +6065,7 @@ The minimum value for this variable is 4096.", // children, to avoid "too many connections" error in a common setup {"max_connections", OPT_MAX_CONNECTIONS, "The number of simultaneous clients allowed.", (gptr*) &max_connections, - (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 16384, 0, 1, + (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, "Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.", @@ -6276,6 +6356,12 @@ The minimum value for this variable is 4096.", "Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.", (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG, DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0}, +#if HAVE_POOL_OF_THREADS == 1 + {"thread_pool_size", OPT_THREAD_CACHE_SIZE, + "How many threads we should create to handle query requests in case of 'thread_handling=pool-of-threads'", + (gptr*) &thread_pool_size, (gptr*) &thread_pool_size, 0, GET_ULONG, + REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, +#endif {"thread_stack", OPT_THREAD_STACK, "The stack size for each thread.", (gptr*) &thread_stack, (gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, @@ -6300,6 +6386,10 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.trans_prealloc_size, (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, + {"thread_handling", OPT_THREAD_HANDLING, + "Define threads usage for handling queries: " + "one-thread-per-connection or no-threads", 0, 0, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT, "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).", (gptr*) &global_system_variables.updatable_views_with_limit, @@ -7241,7 +7331,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'T': test_flags= argument ? (uint) atoi(argument) : 0; - test_flags&= ~TEST_NO_THREADS; opt_endinfo=1; break; case (int) OPT_BIG_TABLES: @@ -7473,11 +7562,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_skip_show_db=1; opt_specialflag|=SPECIAL_SKIP_SHOW_DB; break; -#ifdef ONE_THREAD - case (int) OPT_ONE_THREAD: - test_flags |= TEST_NO_THREADS; -#endif - break; case (int) OPT_WANT_CORE: test_flags |= TEST_CORE_ON_SIGNAL; break; @@ -7723,6 +7807,23 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), sql_mode); break; } + case OPT_ONE_THREAD: + global_system_variables.thread_handling= 2; + break; + case OPT_THREAD_HANDLING: + { + if ((global_system_variables.thread_handling= + find_type(argument, &thread_handling_typelib, 2)) <= 0 || + (global_system_variables.thread_handling == SCHEDULER_POOL_OF_THREADS + && !HAVE_POOL_OF_THREADS)) + { + /* purecov: begin tested */ + fprintf(stderr,"Unknown/unsupported thread-handling: %s\n",argument); + exit(1); + /* purecov: end */ + } + break; + } case OPT_FT_BOOLEAN_SYNTAX: if (ft_boolean_check_syntax_string((byte*) argument)) { @@ -7843,6 +7944,7 @@ static void get_options(int argc,char **argv) if (mysqld_chroot) set_root(mysqld_chroot); #else + global_system_variables.thread_handling = SCHEDULER_NO_THREADS; max_allowed_packet= global_system_variables.max_allowed_packet; net_buffer_length= global_system_variables.net_buffer_length; #endif @@ -7873,6 +7975,17 @@ static void get_options(int argc,char **argv) &global_system_variables.datetime_format)) exit(1); +#ifdef EMBEDDED_LIBRARY + one_thread_scheduler(&thread_scheduler); +#else + if (global_system_variables.thread_handling <= + SCHEDULER_ONE_THREAD_PER_CONNECTION) + one_thread_per_connection_scheduler(&thread_scheduler); + else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS) + one_thread_scheduler(&thread_scheduler); + else + pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */ +#endif } @@ -8213,5 +8326,3 @@ template class I_List<NAMED_LIST>; template class I_List<Statement>; template class I_List_iterator<Statement>; #endif - - diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej deleted file mode 100644 index 62f0357622d..00000000000 --- a/sql/mysqld.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 5316,5322 **** - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, ---- 5336,5342 ---- - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index e9533495650..2156888b8cf 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -47,9 +47,6 @@ #include <violite.h> #include <signal.h> #include <errno.h> -#ifdef __WIN__ -#include <winsock.h> -#endif #ifdef __NETWARE__ #include <sys/select.h> #endif diff --git a/sql/parse_file.cc b/sql/parse_file.cc index c36e16e0553..f5b62e3afe2 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -228,7 +228,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, if (dir) { - fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME); + fn_format(path, file_name->str, dir->str, "", MY_UNPACK_FILENAME); path_end= strlen(path); } else diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 16b00cab516..934a6821514 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -73,23 +73,19 @@ static int init_failsafe_rpl_thread(THD* thd) thd->net.read_timeout = slave_net_timeout; thd->max_client_packet_length=thd->net.max_packet; pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id = thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); if (init_thr_lock() || thd->store_globals()) { + /* purecov: begin inspected */ close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed? statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); + one_thread_per_connection_end(thd,0); DBUG_RETURN(-1); + /* purecov: end */ } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - thd->mem_root->free= thd->mem_root->used= 0; if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; diff --git a/sql/scheduler.cc b/sql/scheduler.cc new file mode 100644 index 00000000000..b05bdf4756f --- /dev/null +++ b/sql/scheduler.cc @@ -0,0 +1,88 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Implementation for the thread scheduler +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma implementation +#endif + +#include <mysql_priv.h> + +/* + 'Dummy' functions to be used when we don't need any handling for a scheduler + event + */ + +static bool init_dummy(void) {return 0;} +static void post_kill_dummy(THD* thd) {} +static void end_dummy(void) {} +static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; } + +/* + Initialize default scheduler with dummy functions so that setup functions + only need to declare those that are relvant for their usage +*/ + +scheduler_functions::scheduler_functions() + :init(init_dummy), + init_new_connection_thread(init_new_connection_handler_thread), + add_connection(0), // Must be defined + post_kill_notification(post_kill_dummy), + end_thread(end_thread_dummy), end(end_dummy) +{} + + +/* + End connection, in case when we are using 'no-threads' +*/ + +static bool no_threads_end(THD *thd, bool put_in_cache) +{ + unlink_thd(thd); + pthread_mutex_unlock(&LOCK_thread_count); + return 1; // Abort handle_one_connection +} + + +/* + Initailize scheduler for --thread-handling=no-threads +*/ + +void one_thread_scheduler(scheduler_functions* func) +{ + func->max_threads= 1; +#ifndef EMBEDDED_LIBRARY + func->add_connection= handle_connection_in_main_thread; +#endif + func->init_new_connection_thread= init_dummy; + func->end_thread= no_threads_end; +} + + +/* + Initialize scheduler for --thread-handling=one-thread-per-connection +*/ + +#ifndef EMBEDDED_LIBRARY +void one_thread_per_connection_scheduler(scheduler_functions* func) +{ + func->max_threads= max_connections; + func->add_connection= create_thread_to_handle_connection; + func->end_thread= one_thread_per_connection_end; +} +#endif /* EMBEDDED_LIBRARY */ diff --git a/sql/scheduler.h b/sql/scheduler.h new file mode 100644 index 00000000000..8351cefda4c --- /dev/null +++ b/sql/scheduler.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Classes for the thread scheduler +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface +#endif + +class THD; + +/* Functions used when manipulating threads */ + +class scheduler_functions +{ +public: + uint max_threads; + bool (*init)(void); + bool (*init_new_connection_thread)(void); + void (*add_connection)(THD *thd); + void (*post_kill_notification)(THD *thd); + bool (*end_thread)(THD *thd, bool cache_thread); + void (*end)(void); + scheduler_functions(); +}; + +enum scheduler_types +{ + SCHEDULER_ONE_THREAD_PER_CONNECTION=1, + SCHEDULER_NO_THREADS, + SCHEDULER_POOL_OF_THREADS +}; + +void one_thread_per_connection_scheduler(scheduler_functions* func); +void one_thread_scheduler(scheduler_functions* func); + +enum pool_command_op +{ + NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP +}; + +#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */ +#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A) + +class thd_scheduler +{}; diff --git a/sql/set_var.cc b/sql/set_var.cc index 55fbeac5622..ad5559165f3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -396,6 +396,10 @@ sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", &SV::trans_prealloc_size, 0, fix_trans_mem_root); +sys_var_thd_enum sys_thread_handling("thread_handling", + &SV::thread_handling, + &thread_handling_typelib, + NULL); #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", @@ -464,6 +468,10 @@ sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout", &table_lock_wait_timeout); sys_var_long_ptr sys_thread_cache_size("thread_cache_size", &thread_cache_size); +#if HAVE_POOL_OF_THREADS == 1 +sys_var_long_ptr sys_thread_pool_size("thread_pool_size", + &thread_pool_size); +#endif sys_var_thd_enum sys_tx_isolation("tx_isolation", &SV::tx_isolation, &tx_isolation_typelib, @@ -1007,6 +1015,10 @@ SHOW_VAR init_vars[]= { #ifdef HAVE_THR_SETCONCURRENCY {"thread_concurrency", (char*) &concurrency, SHOW_LONG}, #endif + {sys_thread_handling.name, (char*) &sys_thread_handling, SHOW_SYS}, +#if HAVE_POOL_OF_THREADS == 1 + {sys_thread_pool_size.name, (char*) &sys_thread_pool_size, SHOW_SYS}, +#endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS}, {"time_zone", (char*) &sys_time_zone, SHOW_SYS}, @@ -2587,7 +2599,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str, file_log= logger.get_log_file_handler(); break; default: - DBUG_ASSERT(0); + assert(0); // Impossible } if (!old_value) @@ -3626,7 +3638,7 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var) */ byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd, - ulong val, + ulonglong val, ulong *len) { char buff[256]; @@ -4002,7 +4014,7 @@ sys_var_event_scheduler::update(THD *thd, set_var *var) res= Events::get_instance()->stop_execution_of_events(); else { - DBUG_ASSERT(0); + assert(0); // Impossible } if (res) my_error(ER_EVENT_SET_VAR_ERROR, MYF(0)); diff --git a/sql/set_var.h b/sql/set_var.h index 338ec5513b0..8887d91ec69 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -440,7 +440,7 @@ public: } void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); - static byte *symbolic_mode_representation(THD *thd, ulong sql_mode, + static byte *symbolic_mode_representation(THD *thd, ulonglong sql_mode, ulong *length); }; diff --git a/sql/slave.cc b/sql/slave.cc index b7bb45d54d5..537604777c8 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1427,9 +1427,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd->slave_thread = 1; set_slave_thread_options(thd); thd->client_capabilities = CLIENT_LOCAL_FILES; - thd->real_id=pthread_self(); pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id = thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; pthread_mutex_unlock(&LOCK_thread_count); if (init_thr_lock() || thd->store_globals()) @@ -1439,12 +1438,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) DBUG_RETURN(-1); } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - if (thd_type == SLAVE_THD_SQL) thd->proc_info= "Waiting for the next event in relay log"; else diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f72cf94c0ac..8bb22824e8f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5162,6 +5162,8 @@ static int handle_grant_struct(uint struct_no, bool drop, user= grant_name->user; host= grant_name->host.hostname; break; + default: + assert(0); } if (! user) user= ""; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fd2e8445132..15d616bdd4f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1078,7 +1078,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) if (!thd->active_transaction()) thd->transaction.xid_state.xid.null(); - /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */ if (!lock_in_use) VOID(pthread_mutex_lock(&LOCK_open)); @@ -1208,11 +1207,12 @@ void close_temporary_tables(THD *thd) const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; uint stub_len= sizeof(stub) - 1; char buf[256]; - memcpy(buf, stub, stub_len); String s_query= String(buf, sizeof(buf), system_charset_info); - bool found_user_tables= false; + bool found_user_tables= FALSE; LINT_INIT(next); + memcpy(buf, stub, stub_len); + /* insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id @@ -1263,10 +1263,13 @@ void close_temporary_tables(THD *thd) { if (is_user_table(table)) { + my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); - /* Loop forward through all tables within the sublist of - common pseudo_thread_id to create single DROP query */ + /* + Loop forward through all tables within the sublist of + common pseudo_thread_id to create single DROP query. + */ for (s_query.length(stub_len); table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; @@ -1292,16 +1295,18 @@ void close_temporary_tables(THD *thd) 0, FALSE); thd->variables.character_set_client= cs_save; /* - Imagine the thread had created a temp table, then was doing a SELECT, and - the SELECT was killed. Then it's not clever to mark the statement above as - "killed", because it's not really a statement updating data, and there - are 99.99% chances it will succeed on slave. - If a real update (one updating a persistent table) was killed on the - master, then this real update will be logged with error_code=killed, - rightfully causing the slave to stop. + Imagine the thread had created a temp table, then was doing a + SELECT, and the SELECT was killed. Then it's not clever to + mark the statement above as "killed", because it's not really + a statement updating data, and there are 99.99% chances it + will succeed on slave. If a real update (one updating a + persistent table) was killed on the master, then this real + update will be logged with error_code=killed, rightfully + causing the slave to stop. */ qinfo.error_code= 0; mysql_bin_log.write(&qinfo); + thd->variables.pseudo_thread_id= save_pseudo_thread_id; } else { @@ -1519,9 +1524,15 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) { if (table->s->table_cache_key.length == key_length && !memcmp(table->s->table_cache_key.str, key, key_length)) + { + DBUG_PRINT("info", + ("Found table. server_id: %u pseudo_thread_id: %lu", + (uint) thd->server_id, + (ulong) thd->variables.pseudo_thread_id)); DBUG_RETURN(table); + } } - DBUG_RETURN(0); // Not a temporary table + DBUG_RETURN(0); // Not a temporary table } @@ -1857,6 +1868,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (table->query_id == thd->query_id || thd->prelocked_mode && table->query_id) { + DBUG_PRINT("error", + ("query_id: %lu server_id: %u pseudo_thread_id: %lu", + (ulong) table->query_id, (uint) thd->server_id, + (ulong) thd->variables.pseudo_thread_id)); my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); DBUG_RETURN(0); } @@ -3507,8 +3522,11 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, uint key_length; TABLE_LIST table_list; DBUG_ENTER("open_temporary_table"); - DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", - db, table_name, path)); + DBUG_PRINT("enter", + ("table: '%s'.'%s' path: '%s' server_id: %u " + "pseudo_thread_id: %lu", + db, table_name, path, + (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id)); table_list.db= (char*) db; table_list.table_name= (char*) table_name; @@ -3795,6 +3813,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, if (nj_col->view_field) { Item *item; + LINT_INIT(arena); if (register_tree_change) arena= thd->activate_stmt_arena_if_needed(&backup); /* @@ -3978,6 +3997,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, { Field *fld; DBUG_ENTER("find_field_in_table_ref"); + DBUG_ASSERT(table_list->alias); + DBUG_ASSERT(name); + DBUG_ASSERT(item_name); DBUG_PRINT("enter", ("table: '%s' field name: '%s' item name: '%s' ref 0x%lx", table_list->alias, name, item_name, (ulong) ref)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d5f81168be3..039fd71d670 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -243,7 +243,7 @@ THD::THD() time_after_lock=(time_t) 0; current_linfo = 0; slave_thread = 0; - variables.pseudo_thread_id= 0; + thread_id= variables.pseudo_thread_id= 0; one_shot_set= 0; file_id = 0; query_id= 0; @@ -267,9 +267,6 @@ THD::THD() cleanup_done= abort_on_warning= no_warnings_for_error= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.m_pending_rows_event= 0; -#ifdef __WIN__ - real_id = 0; -#endif #ifdef SIGNAL_WITH_VIO_CLOSE active_vio = 0; #endif @@ -401,6 +398,8 @@ void THD::change_user(void) void THD::cleanup(void) { DBUG_ENTER("THD::cleanup"); + DBUG_ASSERT(cleanup_done == 0); + #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE if (transaction.xid_state.xa_state == XA_PREPARED) { @@ -436,7 +435,6 @@ void THD::cleanup(void) pthread_mutex_lock(&LOCK_user_locks); item_user_lock_release(ull); pthread_mutex_unlock(&LOCK_user_locks); - ull= 0; } cleanup_done=1; @@ -550,7 +548,9 @@ void THD::awake(THD::killed_state state_to_set) killed= state_to_set; if (state_to_set != THD::KILL_QUERY) { - thr_alarm_kill(real_id); + thr_alarm_kill(thread_id); + if (!slave_thread) + thread_scheduler.post_kill_notification(this); #ifdef SIGNAL_WITH_VIO_CLOSE close_active_vio(); #endif @@ -601,18 +601,19 @@ bool THD::store_globals() Assert that thread_stack is initialized: it's necessary to be able to track stack overrun. */ - DBUG_ASSERT(this->thread_stack); + DBUG_ASSERT(thread_stack); if (my_pthread_setspecific_ptr(THR_THD, this) || my_pthread_setspecific_ptr(THR_MALLOC, &mem_root)) return 1; mysys_var=my_thread_var; - dbug_thread_id=my_thread_id(); /* - By default 'slave_proxy_id' is 'thread_id'. They may later become different - if this is the slave SQL thread. + Let mysqld define the thread id (not mysys) + This allows us to move THD to different threads if needed. */ - variables.pseudo_thread_id= thread_id; + mysys_var->id= thread_id; + real_id= pthread_self(); // For debugging + /* We have to call thr_lock_info_init() again here as THD may have been created in another thread @@ -2511,7 +2512,7 @@ my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data, if (bitmap_is_set(cols,i)) { my_ptrdiff_t const offset= - field->is_null(rec_offset) ? def_offset : rec_offset; + field->is_null((uint) rec_offset) ? def_offset : rec_offset; field->move_field_offset(offset); ptr= (byte*)field->pack((char *) ptr, field->ptr); field->move_field_offset(-offset); @@ -2553,7 +2554,7 @@ namespace { : m_memory(0) { #ifndef DBUG_OFF - m_alloc_checked= false; + m_alloc_checked= FALSE; #endif allocate_memory(table, len1); m_ptr[0]= has_memory() ? m_memory : 0; @@ -2564,7 +2565,7 @@ namespace { : m_memory(0) { #ifndef DBUG_OFF - m_alloc_checked= false; + m_alloc_checked= FALSE; #endif allocate_memory(table, len1 + len2); m_ptr[0]= has_memory() ? m_memory : 0; @@ -2585,7 +2586,7 @@ namespace { */ bool has_memory() const { #ifndef DBUG_OFF - m_alloc_checked= true; + m_alloc_checked= TRUE; #endif return m_memory != 0; } @@ -2594,7 +2595,7 @@ namespace { { DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr)); DBUG_ASSERT(m_ptr[s] != 0); - DBUG_ASSERT(m_alloc_checked == true); + DBUG_ASSERT(m_alloc_checked == TRUE); return m_ptr[s]; } @@ -2624,12 +2625,12 @@ namespace { table->write_row_record= (byte *) alloc_root(&table->mem_root, 2 * maxlen); m_memory= table->write_row_record; - m_release_memory_on_destruction= false; + m_release_memory_on_destruction= FALSE; } else { m_memory= (byte *) my_malloc(total_length, MYF(MY_WME)); - m_release_memory_on_destruction= true; + m_release_memory_on_destruction= TRUE; } } diff --git a/sql/sql_class.h b/sql/sql_class.h index 7babe1eda24..1f5f7aedbb4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -214,7 +214,7 @@ struct system_variables ulong read_rnd_buff_size; ulong div_precincrement; ulong sortbuff_size; - handlerton *table_type; + ulong thread_handling; ulong tx_isolation; ulong completion_type; /* Determines which non-standard SQL behaviour should be enabled */ @@ -231,11 +231,15 @@ struct system_variables ulong trans_prealloc_size; ulong log_warnings; ulong group_concat_max_len; + ulong ndb_autoincrement_prefetch_sz; + ulong ndb_index_stat_cache_entries; + ulong ndb_index_stat_update_freq; + ulong binlog_format; // binlog format for this thd (see enum_binlog_format) /* In slave thread we need to know in behalf of which thread the query is being run to replicate temp tables properly */ - ulong pseudo_thread_id; + my_thread_id pseudo_thread_id; my_bool low_priority_updates; my_bool new_mode; @@ -248,14 +252,12 @@ struct system_variables my_bool ndb_use_exact_count; my_bool ndb_use_transactions; my_bool ndb_index_stat_enable; - ulong ndb_autoincrement_prefetch_sz; - ulong ndb_index_stat_cache_entries; - ulong ndb_index_stat_update_freq; - ulong binlog_format; // binlog format for this thd (see enum_binlog_format) my_bool old_alter_table; my_bool old_passwords; + handlerton *table_type; + /* Only charset part of these variables is sensible */ CHARSET_INFO *character_set_filesystem; CHARSET_INFO *character_set_client; @@ -1064,7 +1066,7 @@ public: } transaction; Field *dup_field; #ifndef __WIN__ - sigset_t signals,block_signals; + sigset_t signals; #endif #ifdef SIGNAL_WITH_VIO_CLOSE Vio* active_vio; @@ -1255,7 +1257,7 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulong thread_id, col_access; + ulong col_access; #ifdef ERROR_INJECT_SUPPORT ulong error_inject_value; @@ -1264,8 +1266,8 @@ public: ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; ulong row_count; // Row counter, mainly for errors and warnings - long dbug_thread_id; - pthread_t real_id; + pthread_t real_id; /* For debugging */ + my_thread_id thread_id; uint tmp_table, global_read_lock; uint server_status,open_options; enum enum_thread_type system_thread; @@ -1629,6 +1631,7 @@ public: *p_db_length= db_length; return FALSE; } + thd_scheduler scheduler; }; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc new file mode 100644 index 00000000000..09ee4962235 --- /dev/null +++ b/sql/sql_connect.cc @@ -0,0 +1,1108 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* + Functions to autenticate and handle reqests for a connection +*/ + +#include "mysql_priv.h" + +#ifdef HAVE_OPENSSL +/* + Without SSL the handshake consists of one packet. This packet + has both client capabilites and scrambled password. + With SSL the handshake might consist of two packets. If the first + packet (client capabilities) has CLIENT_SSL flag set, we have to + switch to SSL and read the second packet. The scrambled password + is in the second packet and client_capabilites field will be ignored. + Maybe it is better to accept flags other than CLIENT_SSL from the + second packet? +*/ +#define SSL_HANDSHAKE_SIZE 2 +#define NORMAL_HANDSHAKE_SIZE 6 +#define MIN_HANDSHAKE_SIZE 2 +#else +#define MIN_HANDSHAKE_SIZE 6 +#endif /* HAVE_OPENSSL */ + +#ifdef __WIN__ +static void test_signal(int sig_ptr) +{ +#if !defined( DBUG_OFF) + MessageBox(NULL,"Test signal","DBUG",MB_OK); +#endif +#if defined(OS2) + fprintf(stderr, "Test signal %d\n", sig_ptr); + fflush(stderr); +#endif +} +static void init_signals(void) +{ + int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; + for (int i=0 ; i < 7 ; i++) + signal( signals[i], test_signal) ; +} +#endif + +/* + Get structure for logging connection data for the current user +*/ + +#ifndef NO_EMBEDDED_ACCESS_CHECKS +static HASH hash_user_connections; + +static int get_or_create_user_conn(THD *thd, const char *user, + const char *host, + USER_RESOURCES *mqh) +{ + int return_val= 0; + uint temp_len, user_len; + char temp_user[USER_HOST_BUFF_SIZE]; + struct user_conn *uc; + + DBUG_ASSERT(user != 0); + DBUG_ASSERT(host != 0); + + user_len= strlen(user); + temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; + (void) pthread_mutex_lock(&LOCK_user_conn); + if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, + (byte*) temp_user, temp_len))) + { + /* First connection for user; Create a user connection object */ + if (!(uc= ((struct user_conn*) + my_malloc(sizeof(struct user_conn) + temp_len+1, + MYF(MY_WME))))) + { + net_send_error(thd, 0, NullS); // Out of memory + return_val= 1; + goto end; + } + uc->user=(char*) (uc+1); + memcpy(uc->user,temp_user,temp_len+1); + uc->host= uc->user + user_len + 1; + uc->len= temp_len; + uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; + uc->user_resources= *mqh; + uc->intime= thd->thr_create_time; + if (my_hash_insert(&hash_user_connections, (byte*) uc)) + { + my_free((char*) uc,0); + net_send_error(thd, 0, NullS); // Out of memory + return_val= 1; + goto end; + } + } + thd->user_connect=uc; + uc->connections++; +end: + (void) pthread_mutex_unlock(&LOCK_user_conn); + return return_val; + +} + + +/* + check if user has already too many connections + + SYNOPSIS + check_for_max_user_connections() + thd Thread handle + uc User connect object + + NOTES + If check fails, we decrease user connection count, which means one + shouldn't call decrease_user_connections() after this function. + + RETURN + 0 ok + 1 error +*/ + +int check_for_max_user_connections(THD *thd, USER_CONN *uc) +{ + int error=0; + DBUG_ENTER("check_for_max_user_connections"); + + (void) pthread_mutex_lock(&LOCK_user_conn); + if (max_user_connections && !uc->user_resources.user_conn && + max_user_connections < (uint) uc->connections) + { + net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); + error=1; + goto end; + } + time_out_user_resource_limits(thd, uc); + if (uc->user_resources.user_conn && + uc->user_resources.user_conn < uc->connections) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, + "max_user_connections", + (long) uc->user_resources.user_conn); + error= 1; + goto end; + } + if (uc->user_resources.conn_per_hour && + uc->user_resources.conn_per_hour <= uc->conn_per_hour) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, + "max_connections_per_hour", + (long) uc->user_resources.conn_per_hour); + error=1; + goto end; + } + uc->conn_per_hour++; + + end: + if (error) + uc->connections--; // no need for decrease_user_connections() here + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_RETURN(error); +} + + +/* + Decrease user connection count + + SYNOPSIS + decrease_user_connections() + uc User connection object + + NOTES + If there is a n user connection object for a connection + (which only happens if 'max_user_connections' is defined or + if someone has created a resource grant for a user), then + the connection count is always incremented on connect. + + The user connect object is not freed if some users has + 'max connections per hour' defined as we need to be able to hold + count over the lifetime of the connection. +*/ + +void decrease_user_connections(USER_CONN *uc) +{ + DBUG_ENTER("decrease_user_connections"); + (void) pthread_mutex_lock(&LOCK_user_conn); + DBUG_ASSERT(uc->connections); + if (!--uc->connections && !mqh_used) + { + /* Last connection for user; Delete it */ + (void) hash_delete(&hash_user_connections,(byte*) uc); + } + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_VOID_RETURN; +} + + +/* + Reset per-hour user resource limits when it has been more than + an hour since they were last checked + + SYNOPSIS: + time_out_user_resource_limits() + thd Thread handler + uc User connection details + + NOTE: + This assumes that the LOCK_user_conn mutex has been acquired, so it is + safe to test and modify members of the USER_CONN structure. +*/ + +void time_out_user_resource_limits(THD *thd, USER_CONN *uc) +{ + time_t check_time = thd->start_time ? thd->start_time : time(NULL); + DBUG_ENTER("time_out_user_resource_limits"); + + /* If more than a hour since last check, reset resource checking */ + if (check_time - uc->intime >= 3600) + { + uc->questions=1; + uc->updates=0; + uc->conn_per_hour=0; + uc->intime=check_time; + } + + DBUG_VOID_RETURN; +} + +/* + Check if maximum queries per hour limit has been reached + returns 0 if OK. +*/ + +bool check_mqh(THD *thd, uint check_command) +{ + bool error= 0; + USER_CONN *uc=thd->user_connect; + DBUG_ENTER("check_mqh"); + DBUG_ASSERT(uc != 0); + + (void) pthread_mutex_lock(&LOCK_user_conn); + + time_out_user_resource_limits(thd, uc); + + /* Check that we have not done too many questions / hour */ + if (uc->user_resources.questions && + uc->questions++ >= uc->user_resources.questions) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", + (long) uc->user_resources.questions); + error=1; + goto end; + } + if (check_command < (uint) SQLCOM_END) + { + /* Check that we have not done too many updates / hour */ + if (uc->user_resources.updates && + (sql_command_flags[check_command] & CF_CHANGES_DATA) && + uc->updates++ >= uc->user_resources.updates) + { + net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + (long) uc->user_resources.updates); + error=1; + goto end; + } + } +end: + (void) pthread_mutex_unlock(&LOCK_user_conn); + DBUG_RETURN(error); +} + +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ + + +/* + Check if user exist and password supplied is correct. + + SYNOPSIS + check_user() + thd thread handle, thd->security_ctx->{host,user,ip} are used + command originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + passwd scrambled password received from client + passwd_len length of scrambled password + db database name to connect to, may be NULL + check_count dont know exactly + + Note, that host, user and passwd may point to communication buffer. + Current implementation does not depend on that, but future changes + should be done with this in mind; 'thd' is INOUT, all other params + are 'IN'. + + RETURN VALUE + 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and + thd->db are updated; OK is sent to client; + -1 access denied or handshake error; error is sent to client; + >0 error, not sent to client +*/ + +int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count) +{ + DBUG_ENTER("check_user"); + +#ifdef NO_EMBEDDED_ACCESS_CHECKS + thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights + /* Change database if necessary */ + if (db && db[0]) + { + /* + thd->db is saved in caller and needs to be freed by caller if this + function returns 0 + */ + thd->reset_db(NULL, 0); + if (mysql_change_db(thd, db, FALSE)) + { + /* Send the error to the client */ + net_send_error(thd); + DBUG_RETURN(-1); + } + } + send_ok(thd); + DBUG_RETURN(0); +#else + + my_bool opt_secure_auth_local; + pthread_mutex_lock(&LOCK_global_system_variables); + opt_secure_auth_local= opt_secure_auth; + pthread_mutex_unlock(&LOCK_global_system_variables); + + /* + If the server is running in secure auth mode, short scrambles are + forbidden. + */ + if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) + { + net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } + if (passwd_len != 0 && + passwd_len != SCRAMBLE_LENGTH && + passwd_len != SCRAMBLE_LENGTH_323) + DBUG_RETURN(ER_HANDSHAKE_ERROR); + + /* + Clear thd->db as it points to something, that will be freed when + connection is closed. We don't want to accidentally free a wrong pointer + if connect failed. Also in case of 'CHANGE USER' failure, current + database will be switched to 'no database selected'. + */ + thd->reset_db(NULL, 0); + + USER_RESOURCES ur; + int res= acl_getroot(thd, &ur, passwd, passwd_len); +#ifndef EMBEDDED_LIBRARY + if (res == -1) + { + /* + This happens when client (new) sends password scrambled with + scramble(), but database holds old value (scrambled with + scramble_323()). Here we please client to send scrambled_password + in old format. + */ + NET *net= &thd->net; + if (opt_secure_auth_local) + { + net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); + general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); + DBUG_RETURN(-1); + } + /* We have to read very specific packet size */ + if (send_old_password_request(thd) || + my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) + { + inc_host_errors(&thd->remote.sin_addr); + DBUG_RETURN(ER_HANDSHAKE_ERROR); + } + /* Final attempt to check the user based on reply */ + /* So as passwd is short, errcode is always >= 0 */ + res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); + } +#endif /*EMBEDDED_LIBRARY*/ + /* here res is always >= 0 */ + if (res == 0) + { + if (!(thd->main_security_ctx.master_access & + NO_ACCESS)) // authentication is OK + { + DBUG_PRINT("info", + ("Capabilities: %lu packet_length: %ld Host: '%s' " + "Login user: '%s' Priv_user: '%s' Using password: %s " + "Access: %lu db: '%s'", + thd->client_capabilities, + thd->max_client_packet_length, + thd->main_security_ctx.host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.priv_user, + passwd_len ? "yes": "no", + thd->main_security_ctx.master_access, + (thd->db ? thd->db : "*none*"))); + + if (check_count) + { + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool count_ok= thread_count <= max_connections + delayed_insert_threads + || (thd->main_security_ctx.master_access & SUPER_ACL); + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!count_ok) + { // too many connections + net_send_error(thd, ER_CON_COUNT_ERROR); + DBUG_RETURN(-1); + } + } + + /* + Log the command before authentication checks, so that the user can + check the log for the tried login tried and also to detect + break-in attempts. + */ + general_log_print(thd, command, + (thd->main_security_ctx.priv_user == + thd->main_security_ctx.user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + db ? db : (char*) ""); + + /* + This is the default access rights for the current database. It's + set to 0 here because we don't have an active database yet (and we + may not have an active database to set. + */ + thd->main_security_ctx.db_access=0; + + /* Don't allow user to connect if he has done too many queries */ + if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || + max_user_connections) && + get_or_create_user_conn(thd, + (opt_old_style_user_limits ? thd->main_security_ctx.user : + thd->main_security_ctx.priv_user), + (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : + thd->main_security_ctx.priv_host), + &ur)) + DBUG_RETURN(-1); + if (thd->user_connect && + (thd->user_connect->user_resources.conn_per_hour || + thd->user_connect->user_resources.user_conn || + max_user_connections) && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(-1); + + /* Change database if necessary */ + if (db && db[0]) + { + if (mysql_change_db(thd, db, FALSE)) + { + /* Send error to the client */ + net_send_error(thd); + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(-1); + } + } + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages + /* Ready to handle queries */ + DBUG_RETURN(0); + } + } + else if (res == 2) // client gave short hash, server has long hash + { + net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } + net_printf_error(thd, ER_ACCESS_DENIED_ERROR, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + DBUG_RETURN(-1); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +/* + Check for maximum allowable user connections, if the mysqld server is + started with corresponding variable that is greater then 0. +*/ + +extern "C" byte *get_key_conn(user_conn *buff, uint *length, + my_bool not_used __attribute__((unused))) +{ + *length=buff->len; + return (byte*) buff->user; +} + + +extern "C" void free_user(struct user_conn *uc) +{ + my_free((char*) uc,MYF(0)); +} + + +void init_max_user_conn(void) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + (void) hash_init(&hash_user_connections,system_charset_info,max_connections, + 0,0, + (hash_get_key) get_key_conn, (hash_free_key) free_user, + 0); +#endif +} + + +void free_max_user_conn(void) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + hash_free(&hash_user_connections); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +void reset_mqh(LEX_USER *lu, bool get_them= 0) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + (void) pthread_mutex_lock(&LOCK_user_conn); + if (lu) // for GRANT + { + USER_CONN *uc; + uint temp_len=lu->user.length+lu->host.length+2; + char temp_user[USER_HOST_BUFF_SIZE]; + + memcpy(temp_user,lu->user.str,lu->user.length); + memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); + temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; + if ((uc = (struct user_conn *) hash_search(&hash_user_connections, + (byte*) temp_user, temp_len))) + { + uc->questions=0; + get_mqh(temp_user,&temp_user[lu->user.length+1],uc); + uc->updates=0; + uc->conn_per_hour=0; + } + } + else + { + /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ + for (uint idx=0;idx < hash_user_connections.records; idx++) + { + USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, + idx); + if (get_them) + get_mqh(uc->user,uc->host,uc); + uc->questions=0; + uc->updates=0; + uc->conn_per_hour=0; + } + } + (void) pthread_mutex_unlock(&LOCK_user_conn); +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ +} + + +void thd_init_client_charset(THD *thd, uint cs_number) +{ + /* + Use server character set and collation if + - opt_character_set_client_handshake is not set + - client has not specified a character set + - client character set is the same as the servers + - client character set doesn't exists in server + */ + if (!opt_character_set_client_handshake || + !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) || + !my_strcasecmp(&my_charset_latin1, + global_system_variables.character_set_client->name, + thd->variables.character_set_client->name)) + { + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.character_set_results= + global_system_variables.character_set_results; + } + else + { + thd->variables.character_set_results= + thd->variables.collation_connection= + thd->variables.character_set_client; + } +} + + +/* + Initialize connection threads +*/ + +bool init_new_connection_handler_thread() +{ + pthread_detach_this_thread(); +#if defined(__WIN__) + init_signals(); +#else + /* Win32 calls this in pthread_create */ + if (my_thread_init()) + return 1; +#endif /* __WIN__ */ + return 0; +} + +/* + Perform handshake, authorize client and update thd ACL variables. + + SYNOPSIS + check_connection() + thd thread handle + + RETURN + 0 success, OK is sent to user, thd is updated. + -1 error, which is sent to user + > 0 error code (not sent to user) +*/ + +#ifndef EMBEDDED_LIBRARY +static int check_connection(THD *thd) +{ + uint connect_errors= 0; + NET *net= &thd->net; + ulong pkt_len= 0; + char *end; + + DBUG_PRINT("info", + ("New connection received on %s", vio_description(net->vio))); +#ifdef SIGNAL_WITH_VIO_CLOSE + thd->set_active_vio(net->vio); +#endif + + if (!thd->main_security_ctx.host) // If TCP/IP connection + { + char ip[30]; + + if (vio_peer_addr(net->vio, ip, &thd->peer_port)) + return (ER_BAD_HOST_ERROR); + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) + return (ER_OUT_OF_RESOURCES); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; + vio_in_addr(net->vio,&thd->remote.sin_addr); + if (!(specialflag & SPECIAL_NO_RESOLVE)) + { + vio_in_addr(net->vio,&thd->remote.sin_addr); + thd->main_security_ctx.host= + ip_to_hostname(&thd->remote.sin_addr, &connect_errors); + /* Cut very long hostnames to avoid possible overflows */ + if (thd->main_security_ctx.host) + { + if (thd->main_security_ctx.host != my_localhost) + thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), + HOSTNAME_LENGTH)]= 0; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + } + if (connect_errors > max_connect_errors) + return(ER_HOST_IS_BLOCKED); + } + DBUG_PRINT("info",("Host: %s ip: %s", + (thd->main_security_ctx.host ? + thd->main_security_ctx.host : "unknown host"), + (thd->main_security_ctx.ip ? + thd->main_security_ctx.ip : "unknown ip"))); + if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) + return(ER_HOST_NOT_PRIVILEGED); + } + else /* Hostname given means that the connection was on a socket */ + { + DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + thd->main_security_ctx.ip= 0; + /* Reset sin_addr */ + bzero((char*) &thd->remote, sizeof(thd->remote)); + } + vio_keepalive(net->vio, TRUE); + { + /* buff[] needs to big enough to hold the server_version variable */ + char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; + ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); + + if (opt_using_transactions) + client_flags|=CLIENT_TRANSACTIONS; +#ifdef HAVE_COMPRESS + client_flags |= CLIENT_COMPRESS; +#endif /* HAVE_COMPRESS */ +#ifdef HAVE_OPENSSL + if (ssl_acceptor_fd) + client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ +#endif /* HAVE_OPENSSL */ + + end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; + int4store((uchar*) end, thd->thread_id); + end+= 4; + /* + So as check_connection is the only entry point to authorization + procedure, scramble is set here. This gives us new scramble for + each handshake. + */ + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); + /* + Old clients does not understand long scrambles, but can ignore packet + tail: that's why first part of the scramble is placed here, and second + part at the end of packet. + */ + end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; + + int2store(end, client_flags); + /* write server characteristics: up to 16 bytes allowed */ + end[2]=(char) default_charset_info->number; + int2store(end+3, thd->server_status); + bzero(end+5, 13); + end+= 18; + /* write scramble tail */ + end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; + + /* At this point we write connection message and read reply */ + if (net_write_command(net, (uchar) protocol_version, "", 0, buff, + (uint) (end-buff)) || + (pkt_len= my_net_read(net)) == packet_error || + pkt_len < MIN_HANDSHAKE_SIZE) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + } +#ifdef _CUSTOMCONFIG_ +#include "_cust_sql_parse.h" +#endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); + if (thd->packet.alloc(thd->variables.net_buffer_length)) + return(ER_OUT_OF_RESOURCES); + + thd->client_capabilities=uint2korr(net->read_pos); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; + thd->max_client_packet_length= uint4korr(net->read_pos+4); + DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); + thd_init_client_charset(thd, (uint) net->read_pos[8]); + thd->update_charset(); + end= (char*) net->read_pos+32; + } + else + { + thd->max_client_packet_length= uint3korr(net->read_pos+2); + end= (char*) net->read_pos+5; + } + + if (thd->client_capabilities & CLIENT_IGNORE_SPACE) + thd->variables.sql_mode|= MODE_IGNORE_SPACE; +#ifdef HAVE_OPENSSL + DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); + if (thd->client_capabilities & CLIENT_SSL) + { + /* Do the SSL layering. */ + if (!ssl_acceptor_fd) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + DBUG_PRINT("info", ("IO layer change in progress...")); + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) + { + DBUG_PRINT("error", ("Failed to accept new SSL connection")); + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + DBUG_PRINT("info", ("Reading user information over SSL layer")); + if ((pkt_len= my_net_read(net)) == packet_error || + pkt_len < NORMAL_HANDSHAKE_SIZE) + { + DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", + pkt_len)); + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + } +#endif /* HAVE_OPENSSL */ + + if (end >= (char*) net->read_pos+ pkt_len +2) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + + if (thd->client_capabilities & CLIENT_INTERACTIVE) + thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; + if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && + opt_using_transactions) + net->return_status= &thd->server_status; + + char *user= end; + char *passwd= strend(user)+1; + uint user_len= passwd - user - 1; + char *db= passwd; + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 + uint dummy_errors; + + /* + Old clients send null-terminated string as password; new clients send + the size (1 byte) + string (not null-terminated). Hence in case of empty + password both send '\0'. + + This strlen() can't be easily deleted without changing protocol. + */ + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? + db + passwd_len + 1 : 0; + /* strlen() can't be easily deleted without changing protocol */ + uint db_len= db ? strlen(db) : 0; + + if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) + { + inc_host_errors(&thd->remote.sin_addr); + return ER_HANDSHAKE_ERROR; + } + + /* Since 4.1 all database names are stored in utf8 */ + if (db) + { + db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, + system_charset_info, + db, db_len, + thd->charset(), &dummy_errors)]= 0; + db= db_buff; + } + + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1, + system_charset_info, user, user_len, + thd->charset(), &dummy_errors)]= '\0'; + user= user_buff; + + /* If username starts and ends in "'", chop them off */ + if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'') + { + user[user_len-1]= 0; + user++; + user_len-= 2; + } + + if (thd->main_security_ctx.user) + x_free(thd->main_security_ctx.user); + if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) + return (ER_OUT_OF_RESOURCES); + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); +} + + +/* + Setup thread to be used with the current thread + + SYNOPSIS + bool setup_connection_thread_globals() + thd Thread/connection handler + + RETURN + 0 ok + 1 Error (out of memory) + In this case we will close the connection and increment status +*/ + +bool setup_connection_thread_globals(THD *thd) +{ + if (thd->store_globals()) + { + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + thread_scheduler.end_thread(thd, 0); + return 1; // Error + } + return 0; +} + + +/* + Autenticate user, with error reporting + + SYNOPSIS + login_connection() + thd Thread handler + + NOTES + Connection is not closed in case of errors + + RETURN + 0 ok + 1 error +*/ + + +bool login_connection(THD *thd) +{ + int error; + NET *net= &thd->net; + Security_context *sctx= thd->security_ctx; + DBUG_ENTER("login_connection"); + DBUG_PRINT("info", ("handle_one_connection called by thread %lu", + thd->thread_id)); + + net->no_send_error= 0; + + /* Use "connect_timeout" value during connection phase */ + net_set_read_timeout(net, connect_timeout); + net_set_write_timeout(net, connect_timeout); + + if ((error=check_connection(thd))) + { // Wrong permissions + if (error > 0) + net_printf_error(thd, error, sctx->host_or_ip); +#ifdef __NT__ + if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) + my_sleep(1000); /* must wait after eof() */ +#endif + statistic_increment(aborted_connects,&LOCK_status); + DBUG_RETURN(1); + } + /* Connect completed, set read/write timeouts back to default */ + net_set_read_timeout(net, thd->variables.net_read_timeout); + net_set_write_timeout(net, thd->variables.net_write_timeout); + DBUG_RETURN(0); +} + + +/* + Close an established connection + + NOTES + This mainly updates status variables +*/ + +void end_connection(THD *thd) +{ + NET *net= &thd->net; + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + if (net->error && net->vio != 0 && net->report_error) + { + Security_context *sctx= thd->security_ctx; + if (!thd->killed && thd->variables.log_warnings > 1) + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), + thd->thread_id,(thd->db ? thd->db : "unconnected"), + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, + (net->last_errno ? ER(net->last_errno) : + ER(ER_UNKNOWN_ERROR))); + net_send_error(thd, net->last_errno, NullS); + statistic_increment(aborted_threads,&LOCK_status); + } + else if (thd->killed) + statistic_increment(aborted_threads,&LOCK_status); +} + + +/* + Initialize THD to handle queries +*/ + +void prepare_new_connection_state(THD* thd) +{ + Security_context *sctx= thd->security_ctx; + +#ifdef __NETWARE__ + netware_reg_user(sctx->ip, sctx->user, "MySQL"); +#endif + + if (thd->variables.max_join_size == HA_POS_ERROR) + thd->options |= OPTION_BIG_SELECTS; + if (thd->client_capabilities & CLIENT_COMPRESS) + thd->net.compress=1; // Use compression + + thd->version= refresh_version; + thd->proc_info= 0; + thd->command= COM_SLEEP; + thd->set_time(); + thd->init_for_queries(); + + if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) + { + execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); + if (thd->query_error) + { + thd->killed= THD::KILL_CONNECTION; + sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), + thd->thread_id,(thd->db ? thd->db : "unconnected"), + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, "init_connect command failed"); + sql_print_warning("%s", thd->net.last_error); + } + thd->proc_info=0; + thd->set_time(); + thd->init_for_queries(); + } +} + + +/* + Thread handler for a connection + + SYNOPSIS + handle_one_connection() + arg Connection object (THD) + + IMPLEMENTATION + This function (normally) does the following: + - Initialize thread + - Initialize THD to be used with this thread + - Authenticate user + - Execute all queries sent on the connection + - Take connection down + - End thread / Handle next connection using thread from thread cache +*/ + +pthread_handler_t handle_one_connection(void *arg) +{ + THD *thd= (THD*) arg; + uint launch_time = + (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); + + if (thread_scheduler.init_new_connection_thread()) + { + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + thread_scheduler.end_thread(thd,0); + return 0; + } + if (launch_time >= slow_launch_time) + statistic_increment(slow_launch_threads,&LOCK_status); + + /* + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. + */ + thd->thread_stack= (char*) &thd; + if (setup_connection_thread_globals(thd)) + return 0; + + for (;;) + { + NET *net= &thd->net; + + if (login_connection(thd)) + goto end_thread; + + prepare_new_connection_state(thd); + + while (!net->error && net->vio != 0 && + !(thd->killed == THD::KILL_CONNECTION)) + { + net->no_send_error= 0; + if (do_command(thd)) + break; + } + end_connection(thd); + +end_thread: + close_connection(thd, 0, 1); + if (thread_scheduler.end_thread(thd,1)) + return 0; // Probably no-threads + + /* + If end_thread() returns, we are either running with + thread-handler=no-threads or this thread has been schedule to + handle the next connection. + */ + thd= current_thd; + thd->thread_stack= (char*) &thd; + } +} +#endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c6309040189..be13fe58882 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -396,6 +396,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) { + res= 1; if (thd->locked_tables) { DBUG_ASSERT(table_list->db); /* Must be set in the parser */ @@ -1895,7 +1896,7 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_detach_this_thread(); /* Add thread to THD list so that's it's visible in 'show processlist' */ pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; thd->end_time(); threads.append(thd); thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; @@ -1926,14 +1927,8 @@ pthread_handler_t handle_delayed_insert(void *arg) strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES)); goto err; } -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif /* open table */ - if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED))) { thd->fatal_error(); // Abort waiting inserts diff --git a/sql/sql_list.h b/sql/sql_list.h index d16fbaf2e50..af30cbe0d6a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -38,6 +38,8 @@ public: static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* never called */ } + static void operator delete[](void *ptr, MEM_ROOT *mem_root) + { /* never called */ } static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } #ifdef HAVE_purify bool dummy; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b45859c4e28..ce7f34e3a06 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -28,24 +28,6 @@ #include "events.h" #include "event_data_objects.h" -#ifdef HAVE_OPENSSL -/* - Without SSL the handshake consists of one packet. This packet - has both client capabilites and scrambled password. - With SSL the handshake might consist of two packets. If the first - packet (client capabilities) has CLIENT_SSL flag set, we have to - switch to SSL and read the second packet. The scrambled password - is in the second packet and client_capabilites field will be ignored. - Maybe it is better to accept flags other than CLIENT_SSL from the - second packet? -*/ -#define SSL_HANDSHAKE_SIZE 2 -#define NORMAL_HANDSHAKE_SIZE 6 -#define MIN_HANDSHAKE_SIZE 2 -#else -#define MIN_HANDSHAKE_SIZE 6 -#endif /* HAVE_OPENSSL */ - /* Used in error handling only */ #define SP_TYPE_STRING(LP) \ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE") @@ -56,11 +38,6 @@ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ "FUNCTION" : "PROCEDURE") -#ifndef NO_EMBEDDED_ACCESS_CHECKS -static void time_out_user_resource_limits(THD *thd, USER_CONN *uc); -static int check_for_max_user_connections(THD *thd, USER_CONN *uc); -static void decrease_user_connections(USER_CONN *uc); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); const char *any_db="*any*"; // Special symbol for check_access @@ -103,20 +80,6 @@ const char *xa_state_names[]={ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" }; -#ifdef __WIN__ -static void test_signal(int sig_ptr) -{ -#if !defined( DBUG_OFF) - MessageBox(NULL,"Test signal","DBUG",MB_OK); -#endif -} -static void init_signals(void) -{ - int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; - for (int i=0 ; i < 7 ; i++) - signal( signals[i], test_signal) ; -} -#endif static void unlock_locked_tables(THD *thd) { @@ -160,6 +123,7 @@ bool end_active_trans(THD *thd) DBUG_RETURN(error); } + bool begin_trans(THD *thd) { int error=0; @@ -211,413 +175,6 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) return 0; } -#ifndef NO_EMBEDDED_ACCESS_CHECKS -static HASH hash_user_connections; - -static int get_or_create_user_conn(THD *thd, const char *user, - const char *host, - USER_RESOURCES *mqh) -{ - int return_val= 0; - uint temp_len, user_len; - char temp_user[USER_HOST_BUFF_SIZE]; - struct user_conn *uc; - - DBUG_ASSERT(user != 0); - DBUG_ASSERT(host != 0); - - user_len= strlen(user); - temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; - (void) pthread_mutex_lock(&LOCK_user_conn); - if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len))) - { - /* First connection for user; Create a user connection object */ - if (!(uc= ((struct user_conn*) - my_malloc(sizeof(struct user_conn) + temp_len+1, - MYF(MY_WME))))) - { - net_send_error(thd, 0, NullS); // Out of memory - return_val= 1; - goto end; - } - uc->user=(char*) (uc+1); - memcpy(uc->user,temp_user,temp_len+1); - uc->host= uc->user + user_len + 1; - uc->len= temp_len; - uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; - uc->user_resources= *mqh; - uc->intime= thd->thr_create_time; - if (my_hash_insert(&hash_user_connections, (byte*) uc)) - { - my_free((char*) uc,0); - net_send_error(thd, 0, NullS); // Out of memory - return_val= 1; - goto end; - } - } - thd->user_connect=uc; - uc->connections++; -end: - (void) pthread_mutex_unlock(&LOCK_user_conn); - return return_val; - -} -#endif /* !NO_EMBEDDED_ACCESS_CHECKS */ - - -/* - Check if user exist and password supplied is correct. - - SYNOPSIS - check_user() - thd thread handle, thd->security_ctx->{host,user,ip} are used - command originator of the check: now check_user is called - during connect and change user procedures; used for - logging. - passwd scrambled password received from client - passwd_len length of scrambled password - db database name to connect to, may be NULL - check_count dont know exactly - - Note, that host, user and passwd may point to communication buffer. - Current implementation does not depend on that, but future changes - should be done with this in mind; 'thd' is INOUT, all other params - are 'IN'. - - RETURN VALUE - 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and - thd->db are updated; OK is sent to client; - -1 access denied or handshake error; error is sent to client; - >0 error, not sent to client -*/ - -int check_user(THD *thd, enum enum_server_command command, - const char *passwd, uint passwd_len, const char *db, - bool check_count) -{ - DBUG_ENTER("check_user"); - -#ifdef NO_EMBEDDED_ACCESS_CHECKS - thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights - /* Change database if necessary */ - if (db && db[0]) - { - /* - thd->db is saved in caller and needs to be freed by caller if this - function returns 0 - */ - thd->reset_db(NULL, 0); - if (mysql_change_db(thd, db, FALSE)) - { - /* Send the error to the client */ - net_send_error(thd); - DBUG_RETURN(-1); - } - } - send_ok(thd); - DBUG_RETURN(0); -#else - - my_bool opt_secure_auth_local; - pthread_mutex_lock(&LOCK_global_system_variables); - opt_secure_auth_local= opt_secure_auth; - pthread_mutex_unlock(&LOCK_global_system_variables); - - /* - If the server is running in secure auth mode, short scrambles are - forbidden. - */ - if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) - { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); - general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); - } - if (passwd_len != 0 && - passwd_len != SCRAMBLE_LENGTH && - passwd_len != SCRAMBLE_LENGTH_323) - DBUG_RETURN(ER_HANDSHAKE_ERROR); - - /* - Clear thd->db as it points to something, that will be freed when - connection is closed. We don't want to accidentally free a wrong pointer - if connect failed. Also in case of 'CHANGE USER' failure, current - database will be switched to 'no database selected'. - */ - thd->reset_db(NULL, 0); - - USER_RESOURCES ur; - int res= acl_getroot(thd, &ur, passwd, passwd_len); -#ifndef EMBEDDED_LIBRARY - if (res == -1) - { - /* - This happens when client (new) sends password scrambled with - scramble(), but database holds old value (scrambled with - scramble_323()). Here we please client to send scrambled_password - in old format. - */ - NET *net= &thd->net; - if (opt_secure_auth_local) - { - net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip); - general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip); - DBUG_RETURN(-1); - } - /* We have to read very specific packet size */ - if (send_old_password_request(thd) || - my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) - { - inc_host_errors(&thd->remote.sin_addr); - DBUG_RETURN(ER_HANDSHAKE_ERROR); - } - /* Final attempt to check the user based on reply */ - /* So as passwd is short, errcode is always >= 0 */ - res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); - } -#endif /*EMBEDDED_LIBRARY*/ - /* here res is always >= 0 */ - if (res == 0) - { - if (!(thd->main_security_ctx.master_access & - NO_ACCESS)) // authentication is OK - { - DBUG_PRINT("info", - ("Capabilities: %lu packet_length: %ld Host: '%s' " - "Login user: '%s' Priv_user: '%s' Using password: %s " - "Access: %lu db: '%s'", - thd->client_capabilities, - thd->max_client_packet_length, - thd->main_security_ctx.host_or_ip, - thd->main_security_ctx.user, - thd->main_security_ctx.priv_user, - passwd_len ? "yes": "no", - thd->main_security_ctx.master_access, - (thd->db ? thd->db : "*none*"))); - - if (check_count) - { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (thd->main_security_ctx.master_access & SUPER_ACL); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - if (!count_ok) - { // too many connections - net_send_error(thd, ER_CON_COUNT_ERROR); - DBUG_RETURN(-1); - } - } - - /* - Log the command before authentication checks, so that the user can - check the log for the tried login tried and also to detect - break-in attempts. - */ - general_log_print(thd, command, - (thd->main_security_ctx.priv_user == - thd->main_security_ctx.user ? - (char*) "%s@%s on %s" : - (char*) "%s@%s as anonymous on %s"), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - db ? db : (char*) ""); - - /* - This is the default access rights for the current database. It's - set to 0 here because we don't have an active database yet (and we - may not have an active database to set. - */ - thd->main_security_ctx.db_access=0; - - /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || - max_user_connections) && - get_or_create_user_conn(thd, - (opt_old_style_user_limits ? thd->main_security_ctx.user : - thd->main_security_ctx.priv_user), - (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : - thd->main_security_ctx.priv_host), - &ur)) - DBUG_RETURN(-1); - if (thd->user_connect && - (thd->user_connect->user_resources.conn_per_hour || - thd->user_connect->user_resources.user_conn || - max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(-1); - - /* Change database if necessary */ - if (db && db[0]) - { - if (mysql_change_db(thd, db, FALSE)) - { - /* Send error to the client */ - net_send_error(thd); - if (thd->user_connect) - decrease_user_connections(thd->user_connect); - DBUG_RETURN(-1); - } - } - send_ok(thd); - thd->password= test(passwd_len); // remember for error messages - /* Ready to handle queries */ - DBUG_RETURN(0); - } - } - else if (res == 2) // client gave short hash, server has long hash - { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); - general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); - } - net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); - general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); - DBUG_RETURN(-1); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - -/* - Check for maximum allowable user connections, if the mysqld server is - started with corresponding variable that is greater then 0. -*/ - -extern "C" byte *get_key_conn(user_conn *buff, uint *length, - my_bool not_used __attribute__((unused))) -{ - *length=buff->len; - return (byte*) buff->user; -} - -extern "C" void free_user(struct user_conn *uc) -{ - my_free((char*) uc,MYF(0)); -} - -void init_max_user_conn(void) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - (void) hash_init(&hash_user_connections,system_charset_info,max_connections, - 0,0, - (hash_get_key) get_key_conn, (hash_free_key) free_user, - 0); -#endif -} - - -/* - check if user has already too many connections - - SYNOPSIS - check_for_max_user_connections() - thd Thread handle - uc User connect object - - NOTES - If check fails, we decrease user connection count, which means one - shouldn't call decrease_user_connections() after this function. - - RETURN - 0 ok - 1 error -*/ - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - -static int check_for_max_user_connections(THD *thd, USER_CONN *uc) -{ - int error=0; - DBUG_ENTER("check_for_max_user_connections"); - - (void) pthread_mutex_lock(&LOCK_user_conn); - if (max_user_connections && !uc->user_resources.user_conn && - max_user_connections < (uint) uc->connections) - { - net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); - error=1; - goto end; - } - time_out_user_resource_limits(thd, uc); - if (uc->user_resources.user_conn && - uc->user_resources.user_conn < uc->connections) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_user_connections", - (long) uc->user_resources.user_conn); - error= 1; - goto end; - } - if (uc->user_resources.conn_per_hour && - uc->user_resources.conn_per_hour <= uc->conn_per_hour) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_connections_per_hour", - (long) uc->user_resources.conn_per_hour); - error=1; - goto end; - } - uc->conn_per_hour++; - - end: - if (error) - uc->connections--; // no need for decrease_user_connections() here - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_RETURN(error); -} - -/* - Decrease user connection count - - SYNOPSIS - decrease_user_connections() - uc User connection object - - NOTES - If there is a n user connection object for a connection - (which only happens if 'max_user_connections' is defined or - if someone has created a resource grant for a user), then - the connection count is always incremented on connect. - - The user connect object is not freed if some users has - 'max connections per hour' defined as we need to be able to hold - count over the lifetime of the connection. -*/ - -static void decrease_user_connections(USER_CONN *uc) -{ - DBUG_ENTER("decrease_user_connections"); - (void) pthread_mutex_lock(&LOCK_user_conn); - DBUG_ASSERT(uc->connections); - if (!--uc->connections && !mqh_used) - { - /* Last connection for user; Delete it */ - (void) hash_delete(&hash_user_connections,(byte*) uc); - } - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_VOID_RETURN; -} - -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ - - -void free_max_user_conn(void) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - hash_free(&hash_user_connections); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - - /* Mark all commands that somehow changes a table @@ -701,402 +258,6 @@ bool is_update_query(enum enum_sql_command command) return (sql_command_flags[command] & CF_CHANGES_DATA) != 0; } -/* - Reset per-hour user resource limits when it has been more than - an hour since they were last checked - - SYNOPSIS: - time_out_user_resource_limits() - thd Thread handler - uc User connection details - - NOTE: - This assumes that the LOCK_user_conn mutex has been acquired, so it is - safe to test and modify members of the USER_CONN structure. -*/ - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - -static void time_out_user_resource_limits(THD *thd, USER_CONN *uc) -{ - time_t check_time = thd->start_time ? thd->start_time : time(NULL); - DBUG_ENTER("time_out_user_resource_limits"); - - /* If more than a hour since last check, reset resource checking */ - if (check_time - uc->intime >= 3600) - { - uc->questions=1; - uc->updates=0; - uc->conn_per_hour=0; - uc->intime=check_time; - } - - DBUG_VOID_RETURN; -} - -/* - Check if maximum queries per hour limit has been reached - returns 0 if OK. -*/ - -static bool check_mqh(THD *thd, uint check_command) -{ - bool error= 0; - USER_CONN *uc=thd->user_connect; - DBUG_ENTER("check_mqh"); - DBUG_ASSERT(uc != 0); - - (void) pthread_mutex_lock(&LOCK_user_conn); - - time_out_user_resource_limits(thd, uc); - - /* Check that we have not done too many questions / hour */ - if (uc->user_resources.questions && - uc->questions++ >= uc->user_resources.questions) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", - (long) uc->user_resources.questions); - error=1; - goto end; - } - if (check_command < (uint) SQLCOM_END) - { - /* Check that we have not done too many updates / hour */ - if (uc->user_resources.updates && - (sql_command_flags[check_command] & CF_CHANGES_DATA) && - uc->updates++ >= uc->user_resources.updates) - { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", - (long) uc->user_resources.updates); - error=1; - goto end; - } - } -end: - (void) pthread_mutex_unlock(&LOCK_user_conn); - DBUG_RETURN(error); -} - -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ - - -static void reset_mqh(LEX_USER *lu, bool get_them= 0) -{ -#ifndef NO_EMBEDDED_ACCESS_CHECKS - (void) pthread_mutex_lock(&LOCK_user_conn); - if (lu) // for GRANT - { - USER_CONN *uc; - uint temp_len=lu->user.length+lu->host.length+2; - char temp_user[USER_HOST_BUFF_SIZE]; - - memcpy(temp_user,lu->user.str,lu->user.length); - memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); - temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; - if ((uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len))) - { - uc->questions=0; - get_mqh(temp_user,&temp_user[lu->user.length+1],uc); - uc->updates=0; - uc->conn_per_hour=0; - } - } - else - { - /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ - for (uint idx=0;idx < hash_user_connections.records; idx++) - { - USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, - idx); - if (get_them) - get_mqh(uc->user,uc->host,uc); - uc->questions=0; - uc->updates=0; - uc->conn_per_hour=0; - } - } - (void) pthread_mutex_unlock(&LOCK_user_conn); -#endif /* NO_EMBEDDED_ACCESS_CHECKS */ -} - -void thd_init_client_charset(THD *thd, uint cs_number) -{ - /* - Use server character set and collation if - - opt_character_set_client_handshake is not set - - client has not specified a character set - - client character set is the same as the servers - - client character set doesn't exists in server - */ - if (!opt_character_set_client_handshake || - !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) || - !my_strcasecmp(&my_charset_latin1, - global_system_variables.character_set_client->name, - thd->variables.character_set_client->name)) - { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.character_set_results= - global_system_variables.character_set_results; - } - else - { - thd->variables.character_set_results= - thd->variables.collation_connection= - thd->variables.character_set_client; - } -} - - -/* - Perform handshake, authorize client and update thd ACL variables. - SYNOPSIS - check_connection() - thd thread handle - - RETURN - 0 success, OK is sent to user, thd is updated. - -1 error, which is sent to user - > 0 error code (not sent to user) -*/ - -#ifndef EMBEDDED_LIBRARY -static int check_connection(THD *thd) -{ - uint connect_errors= 0; - NET *net= &thd->net; - ulong pkt_len= 0; - char *end; - - DBUG_PRINT("info", - ("New connection received on %s", vio_description(net->vio))); -#ifdef SIGNAL_WITH_VIO_CLOSE - thd->set_active_vio(net->vio); -#endif - - if (!thd->main_security_ctx.host) // If TCP/IP connection - { - char ip[30]; - - if (vio_peer_addr(net->vio, ip, &thd->peer_port)) - return (ER_BAD_HOST_ERROR); - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) - return (ER_OUT_OF_RESOURCES); - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; - vio_in_addr(net->vio,&thd->remote.sin_addr); - if (!(specialflag & SPECIAL_NO_RESOLVE)) - { - vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->main_security_ctx.host= - ip_to_hostname(&thd->remote.sin_addr, &connect_errors); - /* Cut very long hostnames to avoid possible overflows */ - if (thd->main_security_ctx.host) - { - if (thd->main_security_ctx.host != my_localhost) - thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), - HOSTNAME_LENGTH)]= 0; - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; - } - if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); - } - DBUG_PRINT("info",("Host: %s ip: %s", - (thd->main_security_ctx.host ? - thd->main_security_ctx.host : "unknown host"), - (thd->main_security_ctx.ip ? - thd->main_security_ctx.ip : "unknown ip"))); - if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) - return(ER_HOST_NOT_PRIVILEGED); - } - else /* Hostname given means that the connection was on a socket */ - { - DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); - thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; - thd->main_security_ctx.ip= 0; - /* Reset sin_addr */ - bzero((char*) &thd->remote, sizeof(thd->remote)); - } - vio_keepalive(net->vio, TRUE); - { - /* buff[] needs to big enough to hold the server_version variable */ - char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; - ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); - - if (opt_using_transactions) - client_flags|=CLIENT_TRANSACTIONS; -#ifdef HAVE_COMPRESS - client_flags |= CLIENT_COMPRESS; -#endif /* HAVE_COMPRESS */ -#ifdef HAVE_OPENSSL - if (ssl_acceptor_fd) - client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ -#endif /* HAVE_OPENSSL */ - - end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; - int4store((uchar*) end, thd->thread_id); - end+= 4; - /* - So as check_connection is the only entry point to authorization - procedure, scramble is set here. This gives us new scramble for - each handshake. - */ - create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); - /* - Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of the scramble is placed here, and second - part at the end of packet. - */ - end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; - - int2store(end, client_flags); - /* write server characteristics: up to 16 bytes allowed */ - end[2]=(char) default_charset_info->number; - int2store(end+3, thd->server_status); - bzero(end+5, 13); - end+= 18; - /* write scramble tail */ - end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, - SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; - - /* At this point we write connection message and read reply */ - if (net_write_command(net, (uchar) protocol_version, "", 0, buff, - (uint) (end-buff)) || - (pkt_len= my_net_read(net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - } -#ifdef _CUSTOMCONFIG_ -#include "_cust_sql_parse.h" -#endif - if (connect_errors) - reset_host_errors(&thd->remote.sin_addr); - if (thd->packet.alloc(thd->variables.net_buffer_length)) - return(ER_OUT_OF_RESOURCES); - - thd->client_capabilities=uint2korr(net->read_pos); - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; - thd->max_client_packet_length= uint4korr(net->read_pos+4); - DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - thd_init_client_charset(thd, (uint) net->read_pos[8]); - thd->update_charset(); - end= (char*) net->read_pos+32; - } - else - { - thd->max_client_packet_length= uint3korr(net->read_pos+2); - end= (char*) net->read_pos+5; - } - - if (thd->client_capabilities & CLIENT_IGNORE_SPACE) - thd->variables.sql_mode|= MODE_IGNORE_SPACE; -#ifdef HAVE_OPENSSL - DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); - if (thd->client_capabilities & CLIENT_SSL) - { - /* Do the SSL layering. */ - if (!ssl_acceptor_fd) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) - { - DBUG_PRINT("error", ("Failed to accept new SSL connection")); - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - DBUG_PRINT("info", ("Reading user information over SSL layer")); - if ((pkt_len= my_net_read(net)) == packet_error || - pkt_len < NORMAL_HANDSHAKE_SIZE) - { - DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", - pkt_len)); - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - } -#endif - - if (end >= (char*) net->read_pos+ pkt_len +2) - { - inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); - } - - if (thd->client_capabilities & CLIENT_INTERACTIVE) - thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; - if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && - opt_using_transactions) - net->return_status= &thd->server_status; - - char *user= end; - char *passwd= strend(user)+1; - uint user_len= passwd - user - 1; - char *db= passwd; - char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 - char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 - uint dummy_errors; - - /* - Old clients send null-terminated string as password; new clients send - the size (1 byte) + string (not null-terminated). Hence in case of empty - password both send '\0'. - - This strlen() can't be easily deleted without changing protocol. - */ - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); - db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? - db + passwd_len + 1 : 0; - /* strlen() can't be easily deleted without changing protocol */ - uint db_len= db ? strlen(db) : 0; - - if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - - /* Since 4.1 all database names are stored in utf8 */ - if (db) - { - db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, - system_charset_info, - db, db_len, - thd->charset(), &dummy_errors)]= 0; - db= db_buff; - } - - user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1, - system_charset_info, user, user_len, - thd->charset(), &dummy_errors)]= '\0'; - user= user_buff; - - /* If username starts and ends in "'", chop them off */ - if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'') - { - user[user_len-1]= 0; - user++; - user_len-= 2; - } - - if (thd->main_security_ctx.user) - x_free(thd->main_security_ctx.user); - if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) - return (ER_OUT_OF_RESOURCES); - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); -} - void execute_init_command(THD *thd, sys_var_str *init_command_var, rw_lock_t *var_mutex) @@ -1129,153 +290,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -pthread_handler_t handle_one_connection(void *arg) -{ - THD *thd=(THD*) arg; - uint launch_time = - (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); - if (launch_time >= slow_launch_time) - statistic_increment(slow_launch_threads,&LOCK_status ); - - pthread_detach_this_thread(); - -#if !defined( __WIN__) // Win32 calls this in pthread_create - /* The following calls needs to be done before we call DBUG_ macros */ - if (!(test_flags & TEST_NO_THREADS) & my_thread_init()) - { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); - return 0; - } -#endif - - /* - handle_one_connection() is the only way a thread would start - and would always be on top of the stack, therefore, the thread - stack always starts at the address of the first local variable - of handle_one_connection, which is thd. We need to know the - start of the stack so that we could check for stack overruns. - */ - DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n", - thd->thread_id)); - /* now that we've called my_thread_init(), it is safe to call DBUG_* */ - -#if defined(__WIN__) - init_signals(); -#elif !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif - thd->thread_stack= (char*) &thd; - if (thd->store_globals()) - { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - end_thread(thd,0); - return 0; - } - - do - { - int error; - NET *net= &thd->net; - Security_context *sctx= thd->security_ctx; - net->no_send_error= 0; - - /* Use "connect_timeout" value during connection phase */ - net_set_read_timeout(net, connect_timeout); - net_set_write_timeout(net, connect_timeout); - - if ((error=check_connection(thd))) - { // Wrong permissions - if (error > 0) - net_printf_error(thd, error, sctx->host_or_ip); -#ifdef __NT__ - if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) - my_sleep(1000); /* must wait after eof() */ -#endif - statistic_increment(aborted_connects,&LOCK_status); - goto end_thread; - } -#ifdef __NETWARE__ - netware_reg_user(sctx->ip, sctx->user, "MySQL"); -#endif - if (thd->variables.max_join_size == HA_POS_ERROR) - thd->options |= OPTION_BIG_SELECTS; - if (thd->client_capabilities & CLIENT_COMPRESS) - net->compress=1; // Use compression - - thd->version= refresh_version; - thd->proc_info= 0; - thd->command= COM_SLEEP; - thd->set_time(); - thd->init_for_queries(); - - if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) - { - execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); - if (thd->query_error) - { - thd->killed= THD::KILL_CONNECTION; - sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), - thd->thread_id,(thd->db ? thd->db : "unconnected"), - sctx->user ? sctx->user : "unauthenticated", - sctx->host_or_ip, "init_connect command failed"); - sql_print_warning("%s", net->last_error); - } - thd->proc_info=0; - thd->set_time(); - thd->init_for_queries(); - } - - /* Connect completed, set read/write timeouts back to tdefault */ - net_set_read_timeout(net, thd->variables.net_read_timeout); - net_set_write_timeout(net, thd->variables.net_write_timeout); - - while (!net->error && net->vio != 0 && - !(thd->killed == THD::KILL_CONNECTION)) - { - net->no_send_error= 0; - if (do_command(thd)) - break; - } - if (thd->user_connect) - decrease_user_connections(thd->user_connect); - if (net->error && net->vio != 0 && net->report_error) - { - if (!thd->killed && thd->variables.log_warnings > 1) - sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), - thd->thread_id,(thd->db ? thd->db : "unconnected"), - sctx->user ? sctx->user : "unauthenticated", - sctx->host_or_ip, - (net->last_errno ? ER(net->last_errno) : - ER(ER_UNKNOWN_ERROR))); - net_send_error(thd, net->last_errno, NullS); - statistic_increment(aborted_threads,&LOCK_status); - } - else if (thd->killed) - { - statistic_increment(aborted_threads,&LOCK_status); - } - -end_thread: - close_connection(thd, 0, 1); - end_thread(thd,1); - /* - If end_thread returns, we are either running with --one-thread - or this thread has been schedule to handle the next query - */ - thd= current_thd; - thd->thread_stack= (char*) &thd; - } while (!(test_flags & TEST_NO_THREADS)); - /* The following is only executed if we are not using --one-thread */ - return(0); /* purecov: deadcode */ -} - -#endif /* EMBEDDED_LIBRARY */ - /* Execute commands from bootstrap_file. Used when creating the initial grant tables @@ -1302,11 +316,6 @@ pthread_handler_t handle_bootstrap(void *arg) #ifndef EMBEDDED_LIBRARY pthread_detach_this_thread(); thd->thread_stack= (char*) &thd; -#if !defined(__WIN__) && !defined(__NETWARE__) - sigset_t set; - VOID(sigemptyset(&set)); // Get mask in use - VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); -#endif #endif /* EMBEDDED_LIBRARY */ if (thd->variables.max_join_size == HA_POS_ERROR) @@ -2085,7 +1094,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ enum mysql_enum_shutdown_level level= (enum mysql_enum_shutdown_level) (uchar) packet[0]; - DBUG_PRINT("quit",("Got shutdown command for level %u", level)); if (level == SHUTDOWN_DEFAULT) level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) @@ -4230,7 +3238,7 @@ end_with_restore_list: { if (!(user= get_current_user(thd, tmp_user))) goto error; - reset_mqh(user); + reset_mqh(user, 0); } } } @@ -6580,6 +5588,7 @@ bool st_select_lex::init_nested_join(THD *thd) join_list->push_front(ptr); ptr->embedding= embedding; ptr->join_list= join_list; + ptr->alias= (char*) "(nested_join)"; embedding= ptr; join_list= &nested_join->join_list; join_list->empty(); @@ -6664,6 +5673,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) ptr->embedding= embedding; ptr->join_list= join_list; + ptr->alias= (char*) "(nest_last_join)"; embedded_list= &nested_join->join_list; embedded_list->empty(); @@ -7158,7 +6168,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } #endif if (options & REFRESH_USER_RESOURCES) - reset_mqh((LEX_USER *) NULL); + reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ *write_to_binlog= tmp_write_to_binlog; return result; } diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej deleted file mode 100644 index 6e2bd03867d..00000000000 --- a/sql/sql_parse.cc.rej +++ /dev/null @@ -1,166 +0,0 @@ -*************** -*** 67,109 **** - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); -- static void remove_escape(char *name); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! LEX_STRING command_name[]={ -! (char *)STRING_WITH_LEN("Sleep"), -! (char *)STRING_WITH_LEN("Quit"), -! (char *)STRING_WITH_LEN("Init DB"), -! (char *)STRING_WITH_LEN("Query"), -! (char *)STRING_WITH_LEN("Field List"), -! (char *)STRING_WITH_LEN("Create DB"), -! (char *)STRING_WITH_LEN("Drop DB"), -! (char *)STRING_WITH_LEN("Refresh"), -! (char *)STRING_WITH_LEN("Shutdown"), -! (char *)STRING_WITH_LEN("Statistics"), -! (char *)STRING_WITH_LEN("Processlist"), -! (char *)STRING_WITH_LEN("Connect"), -! (char *)STRING_WITH_LEN("Kill"), -! (char *)STRING_WITH_LEN("Debug"), -! (char *)STRING_WITH_LEN("Ping"), -! (char *)STRING_WITH_LEN("Time"), -! (char *)STRING_WITH_LEN("Delayed insert"), -! (char *)STRING_WITH_LEN("Change user"), -! (char *)STRING_WITH_LEN("Binlog Dump"), -! (char *)STRING_WITH_LEN("Table Dump"), -! (char *)STRING_WITH_LEN("Connect Out"), -! (char *)STRING_WITH_LEN("Register Slave"), -! (char *)STRING_WITH_LEN("Prepare"), -! (char *)STRING_WITH_LEN("Execute"), -! (char *)STRING_WITH_LEN("Long Data"), -! (char *)STRING_WITH_LEN("Close stmt"), -! (char *)STRING_WITH_LEN("Reset stmt"), -! (char *)STRING_WITH_LEN("Set option"), -! (char *)STRING_WITH_LEN("Fetch"), -! (char *)STRING_WITH_LEN("Daemon"), -! (char *)STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ ---- 67,108 ---- - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! const LEX_STRING command_name[]={ -! C_STRING_WITH_LEN("Sleep"), -! C_STRING_WITH_LEN("Quit"), -! C_STRING_WITH_LEN("Init DB"), -! C_STRING_WITH_LEN("Query"), -! C_STRING_WITH_LEN("Field List"), -! C_STRING_WITH_LEN("Create DB"), -! C_STRING_WITH_LEN("Drop DB"), -! C_STRING_WITH_LEN("Refresh"), -! C_STRING_WITH_LEN("Shutdown"), -! C_STRING_WITH_LEN("Statistics"), -! C_STRING_WITH_LEN("Processlist"), -! C_STRING_WITH_LEN("Connect"), -! C_STRING_WITH_LEN("Kill"), -! C_STRING_WITH_LEN("Debug"), -! C_STRING_WITH_LEN("Ping"), -! C_STRING_WITH_LEN("Time"), -! C_STRING_WITH_LEN("Delayed insert"), -! C_STRING_WITH_LEN("Change user"), -! C_STRING_WITH_LEN("Binlog Dump"), -! C_STRING_WITH_LEN("Table Dump"), -! C_STRING_WITH_LEN("Connect Out"), -! C_STRING_WITH_LEN("Register Slave"), -! C_STRING_WITH_LEN("Prepare"), -! C_STRING_WITH_LEN("Execute"), -! C_STRING_WITH_LEN("Long Data"), -! C_STRING_WITH_LEN("Close stmt"), -! C_STRING_WITH_LEN("Reset stmt"), -! C_STRING_WITH_LEN("Set option"), -! C_STRING_WITH_LEN("Fetch"), -! C_STRING_WITH_LEN("Daemon"), -! C_STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ -*************** -*** 1738,1744 **** - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); ---- 1736,1742 ---- - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); -*************** -*** 2315,2321 **** - DBUG_RETURN(1); - } - db= lex->select_lex.db; -- remove_escape(db); // Fix escaped '_' - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); ---- 2312,2317 ---- - DBUG_RETURN(1); - } - db= lex->select_lex.db; - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); -*************** -*** 6310,6345 **** - } - - -- /* Fix escaping of _, % and \ in database and table names (for ODBC) */ -- -- static void remove_escape(char *name) -- { -- if (!*name) // For empty DB names -- return; -- char *to; -- #ifdef USE_MB -- char *strend=name+(uint) strlen(name); -- #endif -- for (to=name; *name ; name++) -- { -- #ifdef USE_MB -- int l; -- if (use_mb(system_charset_info) && -- (l = my_ismbchar(system_charset_info, name, strend))) -- { -- while (l--) -- *to++ = *name++; -- name--; -- continue; -- } -- #endif -- if (*name == '\\' && name[1]) -- name++; // Skip '\\' -- *to++= *name; -- } -- *to=0; -- } -- - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ ---- 6296,6301 ---- - } - - - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 923e851c0ff..dbac53ed5f6 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6731,7 +6731,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, } } else - DBUG_ASSERT(0); + assert(0); /* Find minimum: Do special handling if the interval has left bound in form diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a75b98997eb..1acc08e095d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2054,6 +2054,7 @@ void mysql_sql_stmt_prepare(THD *thd) uint query_len; DBUG_ENTER("mysql_sql_stmt_prepare"); DBUG_ASSERT(thd->protocol == &thd->protocol_simple); + LINT_INIT(query_len); if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { @@ -2242,7 +2243,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) { uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround ulong stmt_id= uint4korr(packet); - ulong flags= (ulong) ((uchar) packet[4]); + ulong flags= (ulong) packet[4]; /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; #ifndef EMBEDDED_LIBRARY diff --git a/sql/sql_select.cc b/sql/sql_select.cc index afea08ecab3..6de7ba1d58b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8264,7 +8264,7 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list, */ if (nested_join->join_list.elements != 1) { - nested_join->nj_map= 1 << first_unused++; + nested_join->nj_map= (nested_join_map) 1 << first_unused++; first_unused= build_bitmap_for_nested_joins(&nested_join->join_list, first_unused); } @@ -9166,7 +9166,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, uint hidden_null_count, hidden_null_pack_length, hidden_field_count; uint blob_count,group_null_items, string_count; uint temp_pool_slot=MY_BIT_NONE; - ulong reclength, string_total_length, fieldnr= 0; + uint fieldnr= 0; + ulong reclength, string_total_length; bool using_unique_constraint= 0; bool use_packed_rows= 0; bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS); @@ -10332,7 +10333,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) else { DBUG_ASSERT(join->tables); - DBUG_ASSERT(join_tab); error= sub_select(join,join_tab,0); if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) error= sub_select(join,join_tab,1); @@ -15200,7 +15200,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, Item_float *filtered; float f; if (examined_rows) - f= 100.0 * join->best_positions[i].records_read / examined_rows; + f= (float) (100.0 * join->best_positions[i].records_read / + examined_rows); else f= 0.0; item_list.push_back((filtered= new Item_float(f))); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 99fb0fd4236..250d9d917eb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1687,10 +1687,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (mysys_var) pthread_mutex_unlock(&mysys_var->mutex); -#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) - if (pthread_kill(tmp->real_id,0)) - tmp->proc_info="*** DEAD ***"; // This shouldn't happen -#endif #ifdef EXTRA_DEBUG thd_info->start_time= tmp->time_after_lock; #else @@ -2942,20 +2938,21 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, if (file->stats.create_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->stats.create_time); + (my_time_t) file->stats.create_time); table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[14]->set_notnull(); } if (file->stats.update_time) { thd->variables.time_zone->gmt_sec_to_TIME(&time, - file->stats.update_time); + (my_time_t) file->stats.update_time); table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[15]->set_notnull(); } if (file->stats.check_time) { - thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time); + thd->variables.time_zone->gmt_sec_to_TIME(&time, + (my_time_t) file->stats.check_time); table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); table->field[16]->set_notnull(); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bbf510a7437..36f0acd8f67 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -460,10 +460,10 @@ static bool write_ddl_log_header() global_ddl_log.num_entries); const_var= FN_LEN; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], - const_var); + (ulong) const_var); const_var= IO_SIZE; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], - const_var); + (ulong) const_var); if (write_ddl_log_file_entry(0UL)) { sql_print_error("Error writing ddl log header"); @@ -3416,16 +3416,11 @@ bool mysql_create_table_internal(THD *thd, { #ifdef FN_DEVCHAR /* check if the table name contains FN_DEVCHAR when defined */ - const char *start= alias; - while (*start != '\0') + if (strchr(alias, FN_DEVCHAR)) { - if (*start == FN_DEVCHAR) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); - DBUG_RETURN(TRUE); - } - start++; - } + my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); + DBUG_RETURN(TRUE); + } #endif path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext, internal_tmp_table ? FN_IS_TMP : 0); @@ -4602,7 +4597,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, Table_ident *table_ident) { TABLE *tmp_table; - char src_path[FN_REFLEN], dst_path[FN_REFLEN], tmp_path[FN_REFLEN]; + char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char src_table_name_buff[FN_REFLEN], src_db_name_buff[FN_REFLEN]; uint dst_path_length; char *db= table->db; @@ -4613,7 +4608,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, bool res= TRUE, unlock_dst_table= FALSE; enum legacy_db_type not_used; HA_CREATE_INFO *create_info; - +#ifdef WITH_PARTITION_STORAGE_ENGINE + char tmp_path[FN_REFLEN]; +#endif TABLE_LIST src_tables_list, dst_tables_list; DBUG_ENTER("mysql_create_like_table"); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 4fc5bde8fdc..9e30cf5878c 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -73,17 +73,18 @@ void print_cached_tables(void) uint idx,count,unused; TABLE *start_link,*lnk; + /* purecov: begin tested */ VOID(pthread_mutex_lock(&LOCK_open)); - puts("DB Table Version Thread L.thread Open Lock"); + puts("DB Table Version Thread Open Lock"); for (idx=unused=0 ; idx < open_cache.records ; idx++) { TABLE *entry=(TABLE*) hash_element(&open_cache,idx); - printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n", - entry->s->db.str, entry->s->table_name.str, entry->s->version, + printf("%-14.14s %-32s%6ld%8ld%6d %s\n", + entry->s->db.str, entry->s->table_name.str, entry->s->version, entry->in_use ? entry->in_use->thread_id : 0L, - entry->in_use ? entry->in_use->dbug_thread_id : 0L, - entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); + entry->db_stat ? 1 : 0, + entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); if (!entry->in_use) unused++; } @@ -110,6 +111,7 @@ void print_cached_tables(void) printf("Error: File hash table is corrupted\n"); fflush(stdout); VOID(pthread_mutex_unlock(&LOCK_open)); + /* purecov: end */ return; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 7675c854b81..622f7b99d33 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -713,7 +713,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, File_parser *parser; path.str= path_buff; - fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME); + fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME); path.length= strlen(path_buff); if (!access(path.str, F_OK)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index aa386dcf09c..9c062407921 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -556,7 +556,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token GLOBAL_SYM /* SQL-2003-R */ %token GRANT /* SQL-2003-R */ %token GRANTS -%token GROUP /* SQL-2003-R */ +%token GROUP_SYM /* SQL-2003-R */ %token GROUP_CONCAT_SYM %token GT_SYM /* OPERATOR */ %token HANDLER_SYM @@ -1505,7 +1505,7 @@ create: { Lex->sql_command = SQLCOM_CREATE_USER; } - | CREATE LOGFILE_SYM GROUP logfile_group_info + | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info { Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP; } @@ -3081,11 +3081,11 @@ trg_event: ALTER TABLESPACE name CHANGE DATAFILE ... ALTER TABLESPACE name ADD DATAFILE ... ALTER TABLESPACE name access_mode - CREATE LOGFILE GROUP name ... - ALTER LOGFILE GROUP name ADD UNDOFILE .. - ALTER LOGFILE GROUP name ADD REDOFILE .. + CREATE LOGFILE GROUP_SYM name ... + ALTER LOGFILE GROUP_SYM name ADD UNDOFILE .. + ALTER LOGFILE GROUP_SYM name ADD REDOFILE .. DROP TABLESPACE name - DROP LOGFILE GROUP name + DROP LOGFILE GROUP_SYM name */ change_tablespace_access: tablespace_name @@ -3107,7 +3107,7 @@ tablespace_info: opt_logfile_group_name: /* empty */ {} - | USE_SYM LOGFILE_SYM GROUP ident + | USE_SYM LOGFILE_SYM GROUP_SYM ident { LEX *lex= Lex; lex->alter_tablespace_info->logfile_group_name= $4.str; @@ -5073,7 +5073,7 @@ alter: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE; } - | ALTER LOGFILE_SYM GROUP alter_logfile_group_info + | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info { LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP; @@ -7552,7 +7552,7 @@ opt_escape: group_clause: /* empty */ - | GROUP BY group_list olap_opt; + | GROUP_SYM BY group_list olap_opt; group_list: group_list ',' order_ident order_dir @@ -8016,7 +8016,7 @@ drop: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE; } - | DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait + | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait { LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP; diff --git a/sql/table.cc.rej b/sql/table.cc.rej deleted file mode 100644 index fd728ba9965..00000000000 --- a/sql/table.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 2246,2252 **** - - bool check_db_name(char *name) - { -! char *start=name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - ---- 2257,2263 ---- - - bool check_db_name(char *name) - { -! char *start= name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - diff --git a/sql/tztime.cc b/sql/tztime.cc index 257d7c6daae..d765e65c01f 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -546,8 +546,8 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset) int yleap; const uint *ip; - days= t / SECS_PER_DAY; - rem= t % SECS_PER_DAY; + days= (long) (t / SECS_PER_DAY); + rem= (long) (t % SECS_PER_DAY); /* We do this as separate step after dividing t, because this diff --git a/sql/udf_example.c b/sql/udf_example.c index 2bb4fe92d2f..d37c6505ced 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -684,7 +684,7 @@ longlong sequence(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args, ****************************************************************************/ #ifdef __WIN__ -#include <winsock.h> +#include <winsock2.h> #else #include <sys/socket.h> #include <netinet/in.h> diff --git a/sql/udf_example.def b/sql/udf_example.def index ee107d58e51..7a87147d7b6 100644 --- a/sql/udf_example.def +++ b/sql/udf_example.def @@ -1,5 +1,4 @@ LIBRARY udf_example -DESCRIPTION 'MySQL Sample for UDF' VERSION 1.0 EXPORTS lookup diff --git a/sql/unireg.cc b/sql/unireg.cc index 5faacb02d5f..d90420313a6 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -913,7 +913,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, field->interval, field->field_name); if (!regfield) + { + error= 1; goto err; // End of memory + } /* save_in_field() will access regfield->table->in_use */ regfield->init(&table); |