summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authormonty@mysql.com/narttu.mysql.fi <>2007-02-23 13:13:55 +0200
committermonty@mysql.com/narttu.mysql.fi <>2007-02-23 13:13:55 +0200
commitf0ae3ce9b97f45b717201764c6af6e4bd4176e5c (patch)
treeaa523ca58b5c098a79faefb22302aa717f4ae942 /sql
parenta5051aa4ebaf48fae5f7b6f52889c3c66a12dd23 (diff)
downloadmariadb-git-f0ae3ce9b97f45b717201764c6af6e4bd4176e5c.tar.gz
Fixed compiler warnings
Fixed compile-pentium64 scripts Fixed wrong estimate of update_with_key_prefix in sql-bench Merge bk-internal.mysql.com:/home/bk/mysql-5.1 into mysql.com:/home/my/mysql-5.1 Fixed unsafe define of uint4korr() Fixed that --extern works with mysql-test-run.pl Small trivial cleanups This also fixes a bug in counting number of rows that are updated when we have many simultanous queries Move all connection handling and command exectuion main loop from sql_parse.cc to sql_connection.cc Split handle_one_connection() into reusable sub functions. Split create_new_thread() into reusable sub functions. Added thread_scheduler; Preliminary interface code for future thread_handling code. Use 'my_thread_id' for internal thread id's Make thr_alarm_kill() to depend on thread_id instead of thread Make thr_abort_locks_for_thread() depend on thread_id instead of thread In store_globals(), set my_thread_var->id to be thd->thread_id. Use my_thread_var->id as basis for my_thread_name() The above changes makes the connection we have between THD and threads more soft. Added a lot of DBUG_PRINT() and DBUG_ASSERT() functions Fixed compiler warnings Fixed core dumps when running with --debug Removed setting of signal masks (was never used) Made event code call pthread_exit() (portability fix) Fixed that event code doesn't call DBUG_xxx functions before my_thread_init() is called. Made handling of thread_id and thd->variables.pseudo_thread_id uniform. Removed one common 'not freed memory' warning from mysqltest Fixed a couple of usage of not initialized warnings (unlikely cases) Suppress compiler warnings from bdb and (for the moment) warnings from ndb
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/Makefile.am10
-rw-r--r--sql/event_scheduler.cc35
-rw-r--r--sql/field.h2
-rw-r--r--sql/ha_ndbcluster.cc6
-rw-r--r--sql/handler.cc6
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item_cmpfunc.cc3
-rw-r--r--sql/item_func.cc18
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/item_timefunc.cc2
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/log.cc8
-rw-r--r--sql/log_event.cc15
-rw-r--r--sql/mysql_priv.h32
-rw-r--r--sql/mysqld.cc325
-rw-r--r--sql/mysqld.cc.rej17
-rw-r--r--sql/parse_file.cc2
-rw-r--r--sql/repl_failsafe.cc12
-rw-r--r--sql/scheduler.cc88
-rw-r--r--sql/scheduler.h60
-rw-r--r--sql/set_var.cc18
-rw-r--r--sql/set_var.h2
-rw-r--r--sql/slave.cc9
-rw-r--r--sql/sql_acl.cc2
-rw-r--r--sql/sql_base.cc52
-rw-r--r--sql/sql_class.cc25
-rw-r--r--sql/sql_class.h23
-rw-r--r--sql/sql_connect.cc1108
-rw-r--r--sql/sql_insert.cc9
-rw-r--r--sql/sql_parse.cc1000
-rw-r--r--sql/sql_parse.cc.rej166
-rw-r--r--sql/sql_partition.cc2
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_select.cc9
-rw-r--r--sql/sql_show.cc11
-rw-r--r--sql/sql_table.cc17
-rw-r--r--sql/sql_test.cc12
-rw-r--r--sql/sql_view.cc2
-rw-r--r--sql/table.cc.rej17
-rw-r--r--sql/tztime.cc4
-rw-r--r--sql/udf_example.def1
-rw-r--r--sql/unireg.cc3
43 files changed, 1680 insertions, 1463 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 f9351358df8..393856e62ba 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;
@@ -6016,7 +6016,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 8e7206aade9..2244aaa5311 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));
@@ -2855,8 +2855,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..0cc0cc3c84d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1926,7 +1926,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/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 5e9ebfcb902..59fa08a4217 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 54d75449cd5..951cf72d653 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 68465c08746..bf6bd374ef8 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/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 f2bd24bd05e..12418915ad7 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1425,9 +1425,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())
@@ -1437,12 +1436,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 0d9653172e0..3d3b51bab42 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -5169,6 +5169,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..53500e3f661 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);
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 9b66d5c5148..6f4cdbba3dd 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 */
@@ -1897,7 +1898,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;
@@ -1928,14 +1929,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_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 a921cd43048..75b3f5ae981 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);
@@ -15196,7 +15196,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..9162e160bff 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);
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/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 2cdc863565a..e236ceb11d7 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.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);