summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@oracle.com>2010-09-03 09:42:51 +0200
committerJon Olav Hauglid <jon.hauglid@oracle.com>2010-09-03 09:42:51 +0200
commitdd4cd40a875e894a741b1d03ce38b52da790684e (patch)
treeb80c06af995e910fd97578c779e4bb8c01f50fcb /sql
parent370eaa56aa8a83cf8335bace2f3ad2755f43e52d (diff)
parent08e1a5b770e099430e046d3dcd5f8d5fe4f1a279 (diff)
downloadmariadb-git-dd4cd40a875e894a741b1d03ce38b52da790684e.tar.gz
Merge from mysql-5.5-bugfixing to mysql-5.5-runtime.
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt3
-rw-r--r--sql/authors.h1
-rw-r--r--sql/ha_partition.cc7
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_sum.cc45
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/log.cc117
-rw-r--r--sql/log.h4
-rw-r--r--sql/mysqld.cc70
-rw-r--r--sql/mysqld.h6
-rw-r--r--sql/opt_range.cc4
-rw-r--r--sql/scheduler.cc167
-rw-r--r--sql/scheduler.h61
-rw-r--r--sql/sql_callback.h43
-rw-r--r--sql/sql_class.cc75
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_connect.cc15
-rw-r--r--sql/sql_connect.h4
-rw-r--r--sql/sql_plugin_services.h16
-rw-r--r--sql/sql_select.cc104
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc19
-rw-r--r--sql/sql_yacc.yy18
-rw-r--r--sql/sys_vars.cc10
-rw-r--r--sql/table.h1
25 files changed, 581 insertions, 221 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 224cf67af7f..9d307da364d 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -271,8 +271,7 @@ IF(WIN32 AND MYSQLD_EXECUTABLE)
COMMAND ${CMAKE_COMMAND}
${CONFIG_PARAM} -P ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
- COMMAND ${CMAKE_COMMAND} -E touch initdb.dep
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
DEPENDS mysqld
)
ADD_CUSTOM_TARGET(initial_database
diff --git a/sql/authors.h b/sql/authors.h
index 5de2659f098..db0ab00fb86 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -93,6 +93,7 @@ struct show_table_authors_st show_table_authors[]= {
{ "Arjen Lentz", "Brisbane, Australia",
"Documentation (2001-2004), Dutch error messages, LOG2()" },
{ "Marc Liyanage", "", "Created Mac OS X packages" },
+ { "Kelly Long", "Denver, CO, USA", "Pool Of Threads" },
{ "Zarko Mocnik", "", "Sorting for Slovenian language" },
{ "Per-Erik Martin", "Uppsala, Sweden", "Stored Procedures (5.0)" },
{ "Alexis Mikhailov", "", "User-defined functions" },
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7891f658f45..e6915b45a97 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2446,9 +2446,14 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
tot_partition_words= (m_tot_parts + 3) / 4;
engine_array= (handlerton **) my_alloca(m_tot_parts * sizeof(handlerton*));
for (i= 0; i < m_tot_parts; i++)
+ {
engine_array[i]= ha_resolve_by_legacy_type(ha_thd(),
(enum legacy_db_type)
- *(uchar *) ((file_buffer) + 12 + i));
+ *(uchar *) ((file_buffer) +
+ 12 + i));
+ if (!engine_array[i])
+ goto err3;
+ }
address_tot_name_len= file_buffer + 12 + 4 * tot_partition_words;
tot_name_words= (uint4korr(address_tot_name_len) + 3) / 4;
if (len_words != (tot_partition_words + tot_name_words + 4))
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 95965668882..6699b2820e6 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2533,6 +2533,8 @@ void Item_func_min_max::fix_length_and_dec()
decimals,
unsigned_flag));
}
+ else if (cmp_type == REAL_RESULT)
+ fix_char_length(float_length(decimals));
cached_field_type= agg_field_type(args, arg_count);
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b05d845dead..b6e5d6d3182 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -434,26 +434,6 @@ void Item_sum::mark_as_sum_func()
}
-void Item_sum::make_field(Send_field *tmp_field)
-{
- if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
- {
- ((Item_field*) args[0])->field->make_field(tmp_field);
- /* For expressions only col_name should be non-empty string. */
- char *empty_string= (char*)"";
- tmp_field->db_name= empty_string;
- tmp_field->org_table_name= empty_string;
- tmp_field->table_name= empty_string;
- tmp_field->org_col_name= empty_string;
- tmp_field->col_name= name;
- if (maybe_null)
- tmp_field->flags&= ~NOT_NULL_FLAG;
- }
- else
- init_make_field(tmp_field, field_type());
-}
-
-
void Item_sum::print(String *str, enum_query_type query_type)
{
/* orig_args is not filled with valid values until fix_fields() */
@@ -984,7 +964,8 @@ bool Aggregator_distinct::add()
{
int error;
copy_fields(tmp_table_param);
- copy_funcs(tmp_table_param->items_to_copy);
+ if (copy_funcs(tmp_table_param->items_to_copy, table->in_use))
+ return TRUE;
for (Field **field=table->field ; *field ; field++)
if ((*field)->is_real_null(0))
@@ -3058,7 +3039,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
tree(item->tree),
unique_filter(item->unique_filter),
table(item->table),
- order(item->order),
context(item->context),
arg_count_order(item->arg_count_order),
arg_count_field(item->arg_count_field),
@@ -3071,6 +3051,24 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
{
quick_group= item->quick_group;
result.set_charset(collation.collation);
+
+ /*
+ Since the ORDER structures pointed to by the elements of the 'order' array
+ may be modified in find_order_in_list() called from
+ Item_func_group_concat::setup(), create a copy of those structures so that
+ such modifications done in this object would not have any effect on the
+ object being copied.
+ */
+ ORDER *tmp;
+ if (!(order= (ORDER **) thd->alloc(sizeof(ORDER *) * arg_count_order +
+ sizeof(ORDER) * arg_count_order)))
+ return;
+ tmp= (ORDER *)(order + arg_count_order);
+ for (uint i= 0; i < arg_count_order; i++, tmp++)
+ {
+ memcpy(tmp, item->order[i], sizeof(ORDER));
+ order[i]= tmp;
+ }
}
@@ -3136,7 +3134,8 @@ bool Item_func_group_concat::add()
if (always_null)
return 0;
copy_fields(tmp_table_param);
- copy_funcs(tmp_table_param->items_to_copy);
+ if (copy_funcs(tmp_table_param->items_to_copy, table->in_use))
+ return TRUE;
for (uint i= 0; i < arg_count_field; i++)
{
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 2a722b93165..06a8c2c58a4 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -427,7 +427,6 @@ public:
forced_const= TRUE;
}
virtual bool const_item() const { return forced_const; }
- void make_field(Send_field *field);
virtual void print(String *str, enum_query_type query_type);
void fix_num_length_and_dec();
diff --git a/sql/log.cc b/sql/log.cc
index 5ca22d154b1..88352706318 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5447,70 +5447,93 @@ void sql_perror(const char *message)
}
+#ifdef __WIN__
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream)
+{
+ int handle_fd;
+ int stream_fd;
+ HANDLE osfh;
+
+ DBUG_ASSERT(filename && (outstream || errstream));
+
+ if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE)
+ return TRUE;
+
+ if ((handle_fd= _open_osfhandle((intptr_t)osfh,
+ _O_APPEND | _O_TEXT)) == -1)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+
+ if (outstream)
+ {
+ stream_fd= _fileno(outstream);
+ if (_dup2(handle_fd, stream_fd) < 0)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+ }
+
+ if (errstream)
+ {
+ stream_fd= _fileno(errstream);
+ if (_dup2(handle_fd, stream_fd) < 0)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+ }
+
+ _close(handle_fd);
+ return FALSE;
+}
+#else
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream)
+{
+ if (outstream && !freopen(filename, "a+", outstream))
+ return TRUE;
+
+ if (errstream && !freopen(filename, "a+", errstream))
+ return TRUE;
+
+ return FALSE;
+}
+#endif
+
+
/*
Unfortunately, there seems to be no good way
to restore the original streams upon failure.
*/
static bool redirect_std_streams(const char *file)
{
- if (freopen(file, "a+", stdout) && freopen(file, "a+", stderr))
- {
- setbuf(stderr, NULL);
- return FALSE;
- }
+ if (reopen_fstreams(file, stdout, stderr))
+ return TRUE;
- return TRUE;
+ setbuf(stderr, NULL);
+ return FALSE;
}
bool flush_error_log()
{
- bool result=0;
+ bool result= 0;
if (opt_error_log)
{
- char err_renamed[FN_REFLEN], *end;
- end= strmake(err_renamed,log_error_file,FN_REFLEN-5);
- strmov(end, "-old");
mysql_mutex_lock(&LOCK_error_log);
-#ifdef __WIN__
- char err_temp[FN_REFLEN+5];
- /*
- On Windows is necessary a temporary file for to rename
- the current error file.
- */
- strxmov(err_temp, err_renamed,"-tmp",NullS);
- my_delete(err_temp, MYF(0));
- if (freopen(err_temp,"a+",stdout))
- {
- int fd;
- size_t bytes;
- uchar buf[IO_SIZE];
-
- freopen(err_temp,"a+",stderr);
- setbuf(stderr, NULL);
- my_delete(err_renamed, MYF(0));
- my_rename(log_error_file, err_renamed, MYF(0));
- redirect_std_streams(log_error_file);
-
- if ((fd= my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
- {
- while ((bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) &&
- bytes != MY_FILE_ERROR)
- my_fwrite(stderr, buf, bytes, MYF(0));
- mysql_file_close(fd, MYF(0));
- }
- my_delete(err_temp, MYF(0));
- }
- else
- result= 1;
-#else
- my_rename(log_error_file, err_renamed, MYF(0));
- if (redirect_std_streams(log_error_file))
- result= 1;
-#endif
+ if (redirect_std_streams(log_error_file))
+ result= 1;
mysql_mutex_unlock(&LOCK_error_log);
}
- return result;
+ return result;
}
void MYSQL_BIN_LOG::signal_update()
diff --git a/sql/log.h b/sql/log.h
index 6e87b6cbade..ebb23deda81 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -394,10 +394,10 @@ public:
/* Use this to start writing a new log file */
void new_file();
- bool write(Log_event* event_info);
+ bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
- bool write_incident(THD *thd, bool lock);
+ bool write_incident(THD *thd, bool lock);
int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
void set_write_error(THD *thd);
bool check_write_error(THD *thd);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d144f7e82aa..6dd74eb299a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -64,7 +64,9 @@
#include "events.h"
#include "sql_audit.h"
#include "probes_mysql.h"
+#include "scheduler.h"
#include "debug_sync.h"
+#include "sql_callback.h"
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
#include "../storage/perfschema/pfs_server.h"
@@ -193,6 +195,9 @@ typedef fp_except fp_except_t;
# endif
#endif
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream);
+
inline void setup_fpu()
{
#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H)
@@ -456,7 +461,7 @@ ulong slave_trans_retries;
uint slave_net_timeout;
ulong slave_exec_mode_options;
ulonglong slave_type_conversions_options;
-ulong thread_cache_size=0, thread_pool_size= 0;
+ulong thread_cache_size=0;
ulong binlog_cache_size=0;
ulonglong max_binlog_cache_size=0;
ulong query_cache_size=0;
@@ -898,8 +903,6 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
-scheduler_functions thread_scheduler;
-
my_bool opt_use_ssl = 0;
char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL,
*opt_ssl_cipher= NULL, *opt_ssl_key= NULL;
@@ -1087,7 +1090,8 @@ static void close_connections(void)
continue;
tmp->killed= THD::KILL_CONNECTION;
- thread_scheduler.post_kill_notification(tmp);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -1100,6 +1104,7 @@ static void close_connections(void)
}
mysql_mutex_unlock(&tmp->mysys_var->mutex);
}
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
@@ -1479,7 +1484,7 @@ void clean_up(bool print_message)
if (print_message && my_default_lc_messages && server_start_time)
sql_print_information(ER_DEFAULT(ER_SHUTDOWN_COMPLETE),my_progname);
cleanup_errmsgs();
- thread_scheduler.end();
+ MYSQL_CALLBACK(thread_scheduler, end, ());
finish_client_errs();
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
@@ -1752,7 +1757,7 @@ static void network_init(void)
DBUG_ENTER("network_init");
LINT_INIT(ret);
- if (thread_scheduler.init())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
unireg_abort(1); /* purecov: inspected */
set_ports();
@@ -2000,7 +2005,7 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
if (thd && ! thd->bootstrap)
{
statistic_increment(killed_threads, &LOCK_status);
- thread_scheduler.end_thread(thd,0); /* purecov: inspected */
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd,0)); /* purecov: inspected */
}
DBUG_VOID_RETURN; /* purecov: deadcode */
}
@@ -2396,7 +2401,7 @@ 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_threads=%u\n", thread_scheduler.max_threads);
+ fprintf(stderr, "max_threads=%u\n", thread_scheduler->max_threads);
fprintf(stderr, "thread_count=%u\n", thread_count);
fprintf(stderr, "connection_count=%u\n", connection_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
@@ -2404,7 +2409,7 @@ 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) *
- thread_scheduler.max_threads +
+ 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");
@@ -2651,7 +2656,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(thread_scheduler.max_threads +
+ init_thr_alarm(thread_scheduler->max_threads +
global_system_variables.max_insert_delayed_threads + 10);
if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
{
@@ -3738,13 +3743,15 @@ static int init_server_components()
opt_error_log= 0; // Too long file name
else
{
+ my_bool res;
#ifndef EMBEDDED_LIBRARY
- if (freopen(log_error_file, "a+", stdout))
+ res= reopen_fstreams(log_error_file, stdout, stderr);
+#else
+ res= reopen_fstreams(log_error_file, NULL, stderr);
#endif
- {
- if (freopen(log_error_file, "a+", stderr))
- setbuf(stderr, NULL);
- }
+
+ if (!res)
+ setbuf(stderr, NULL);
}
}
@@ -4353,23 +4360,6 @@ int mysqld_main(int argc, char **argv)
}
#endif
-#ifdef __WIN__
- /*
- Before performing any socket operation (like retrieving hostname
- in init_common_variables we have to call WSAStartup
- */
- {
- WSADATA WsaData;
- if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
- {
- /* errors are not read yet, so we use english text here */
- my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
- /* Not enough initializations for unireg_abort() */
- return 1;
- }
- }
-#endif /* __WIN__ */
-
if (init_common_variables())
unireg_abort(1); // Will do exit
@@ -4457,8 +4447,8 @@ int mysqld_main(int argc, char **argv)
#ifdef __WIN__
if (!opt_console)
{
- freopen(log_error_file,"a+",stdout);
- freopen(log_error_file,"a+",stderr);
+ if (reopen_fstreams(log_error_file, stdout, stderr))
+ unireg_abort(1);
setbuf(stderr, NULL);
FreeConsole(); // Remove window
}
@@ -5028,7 +5018,7 @@ static void create_new_thread(THD *thd)
thread_count++;
- thread_scheduler.add_connection(thd);
+ MYSQL_CALLBACK(thread_scheduler, add_connection, (thd));
DBUG_VOID_RETURN;
}
@@ -7344,14 +7334,12 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
return 1;
#ifdef EMBEDDED_LIBRARY
- one_thread_scheduler(&thread_scheduler);
+ one_thread_scheduler();
#else
if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)
- one_thread_per_connection_scheduler(&thread_scheduler);
- else if (thread_handling == SCHEDULER_NO_THREADS)
- one_thread_scheduler(&thread_scheduler);
- else
- pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */
+ one_thread_per_connection_scheduler();
+ else /* thread_handling == SCHEDULER_NO_THREADS) */
+ one_thread_scheduler();
#endif
global_system_variables.engine_condition_pushdown=
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 71b52416302..6e81c240f7d 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -28,7 +28,7 @@ class THD;
struct handlerton;
class Time_zone;
-class scheduler_functions;
+struct scheduler_functions;
typedef struct st_mysql_const_lex_string LEX_CSTRING;
typedef struct st_mysql_show_var SHOW_VAR;
@@ -175,7 +175,7 @@ extern ulong binlog_cache_size, open_files_limit;
extern ulonglong max_binlog_cache_size;
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, thread_pool_size;
+extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong back_log;
extern char language[FN_REFLEN];
extern ulong server_id, concurrency;
@@ -207,7 +207,7 @@ extern my_bool old_mode;
extern LEX_STRING opt_init_connect, opt_init_slave;
extern int bootstrap_error;
extern I_List<THD> threads;
-extern scheduler_functions thread_scheduler;
+extern char err_shared_dir[];
extern TYPELIB thread_handling_typelib;
extern my_decimal decimal_zero;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index af5b4b7c7d6..b9819def54d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -5620,7 +5620,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
field_item, (Item*)(intptr)i, inv);
if (inv)
+ {
tree= !tree ? tmp : tree_or(param, tree, tmp);
+ if (tree == NULL)
+ break;
+ }
else
tree= tree_and(param, tree, tmp);
}
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 10009246428..d61a452b99e 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -25,55 +25,103 @@
#include "unireg.h" // REQUIRED: for other includes
#include "scheduler.h"
#include "sql_connect.h" // init_new_connection_handler_thread
+#include "scheduler.h"
+#include "sql_callback.h"
/*
- 'Dummy' functions to be used when we don't need any handling for a scheduler
- event
- */
+ End connection, in case when we are using 'no-threads'
+*/
-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; }
+static bool no_threads_end(THD *thd, bool put_in_cache)
+{
+ unlink_thd(thd);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ return 1; // Abort handle_one_connection
+}
-/*
- Initialize default scheduler with dummy functions so that setup functions
- only need to declare those that are relvant for their usage
+static scheduler_functions one_thread_scheduler_functions=
+{
+ 1, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+#ifndef EMBEDDED_LIBRARY
+ handle_connection_in_main_thread, // add_connection
+#else
+ NULL, // add_connection
+#endif // EMBEDDED_LIBRARY
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ no_threads_end, // end_thread
+ NULL, // end
+};
+
+#ifndef EMBEDDED_LIBRARY
+static scheduler_functions one_thread_per_connection_scheduler_functions=
+{
+ 0, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+ create_thread_to_handle_connection, // add_connection
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ one_thread_per_connection_end, // end_thread
+ NULL, // end
+};
+#endif // EMBEDDED_LIBRARY
+
+
+scheduler_functions *thread_scheduler= NULL;
+
+/** @internal
+ Helper functions to allow mysys to call the thread scheduler when
+ waiting for locks.
*/
-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)
-{}
+/**@{*/
+static void scheduler_wait_begin(void) {
+ MYSQL_CALLBACK(thread_scheduler,
+ thd_wait_begin, (current_thd, THD_WAIT_ROW_TABLE_LOCK));
+}
+
+static void scheduler_wait_end(void) {
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
+}
+/**@}*/
+/**
+ Common scheduler init function.
+
+ The scheduler is either initialized by calling
+ one_thread_scheduler() or one_thread_per_connection_scheduler() in
+ mysqld.cc, so this init function will always be called.
+ */
+static void scheduler_init() {
+ thr_set_lock_wait_callback(scheduler_wait_begin, scheduler_wait_end);
+}
/*
- End connection, in case when we are using 'no-threads'
+ Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-static bool no_threads_end(THD *thd, bool put_in_cache)
+#ifndef EMBEDDED_LIBRARY
+void one_thread_per_connection_scheduler()
{
- unlink_thd(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
- return 1; // Abort handle_one_connection
+ scheduler_init();
+ one_thread_per_connection_scheduler_functions.max_threads= max_connections;
+ thread_scheduler= &one_thread_per_connection_scheduler_functions;
}
-
+#endif
/*
Initailize scheduler for --thread-handling=no-threads
*/
-void one_thread_scheduler(scheduler_functions* func)
+void one_thread_scheduler()
{
- 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;
+ scheduler_init();
+ thread_scheduler= &one_thread_scheduler_functions;
}
@@ -81,11 +129,58 @@ void one_thread_scheduler(scheduler_functions* func)
Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-#ifndef EMBEDDED_LIBRARY
-void one_thread_per_connection_scheduler(scheduler_functions* func)
+/*
+ thd_scheduler keeps the link between THD and events.
+ It's embedded in the THD class.
+*/
+
+thd_scheduler::thd_scheduler()
+ : m_psi(NULL), data(NULL)
+{
+#ifndef DBUG_OFF
+ dbug_explain[0]= '\0';
+ set_explain= FALSE;
+#endif
+}
+
+
+thd_scheduler::~thd_scheduler()
+{
+}
+
+static scheduler_functions *saved_thread_scheduler;
+static uint saved_thread_handling;
+
+extern "C"
+int my_thread_scheduler_set(scheduler_functions *scheduler)
+{
+ DBUG_ASSERT(scheduler != 0);
+
+ if (scheduler == NULL)
+ return 1;
+
+ saved_thread_scheduler= thread_scheduler;
+ saved_thread_handling= thread_handling;
+ thread_scheduler= scheduler;
+ // Scheduler loaded dynamically
+ thread_handling= SCHEDULER_TYPES_COUNT;
+ return 0;
+}
+
+
+extern "C"
+int my_thread_scheduler_reset()
{
- func->max_threads= max_connections;
- func->add_connection= create_thread_to_handle_connection;
- func->end_thread= one_thread_per_connection_end;
+ DBUG_ASSERT(saved_thread_scheduler != NULL);
+
+ if (saved_thread_scheduler == NULL)
+ return 1;
+
+ thread_scheduler= saved_thread_scheduler;
+ thread_handling= saved_thread_handling;
+ saved_thread_scheduler= 0;
+ return 0;
}
-#endif /* EMBEDDED_LIBRARY */
+
+
+
diff --git a/sql/scheduler.h b/sql/scheduler.h
index e7916031a27..40f0e28bc2c 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -28,38 +28,77 @@ class THD;
/* Functions used when manipulating threads */
-class scheduler_functions
+struct scheduler_functions
{
-public:
uint max_threads;
bool (*init)(void);
bool (*init_new_connection_thread)(void);
void (*add_connection)(THD *thd);
+ void (*thd_wait_begin)(THD *thd, int wait_type);
+ void (*thd_wait_end)(THD *thd);
void (*post_kill_notification)(THD *thd);
bool (*end_thread)(THD *thd, bool cache_thread);
void (*end)(void);
- scheduler_functions();
};
+
+/**
+ Scheduler types enumeration.
+
+ The default of --thread-handling is the first one in the
+ thread_handling_names array, this array has to be consistent with
+ the order in this array, so to change default one has to change the
+ first entry in this enum and the first entry in the
+ thread_handling_names array.
+
+ @note The last entry of the enumeration is also used to mark the
+ thread handling as dynamic. In this case the name of the thread
+ handling is fetched from the name of the plugin that implements it.
+*/
enum scheduler_types
{
SCHEDULER_ONE_THREAD_PER_CONNECTION=0,
SCHEDULER_NO_THREADS,
- SCHEDULER_POOL_OF_THREADS
+ SCHEDULER_TYPES_COUNT
};
-void one_thread_per_connection_scheduler(scheduler_functions* func);
-void one_thread_scheduler(scheduler_functions* func);
+void one_thread_per_connection_scheduler();
+void one_thread_scheduler();
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)
-
+/*
+ To be used for pool-of-threads (implemeneted differently on various OSs)
+*/
class thd_scheduler
-{};
+{
+public:
+ /*
+ Thread instrumentation for the user job.
+ This member holds the instrumentation while the user job is not run
+ by a thread.
+
+ Note that this member is not conditionally declared
+ (ifdef HAVE_PSI_INTERFACE), because doing so will change the binary
+ layout of THD, which is exposed to plugin code that may be compiled
+ differently.
+ */
+ PSI_thread *m_psi;
+
+ void *data; /* scheduler-specific data structure */
+
+# ifndef DBUG_OFF
+ char dbug_explain[512];
+ bool set_explain;
+# endif
-#endif /* SCHEDULER_INCLUDED */
+ thd_scheduler();
+ ~thd_scheduler();
+};
+
+extern scheduler_functions *thread_scheduler;
+
+#endif
diff --git a/sql/sql_callback.h b/sql/sql_callback.h
new file mode 100644
index 00000000000..430514d3d7e
--- /dev/null
+++ b/sql/sql_callback.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SQL_CALLBACK_INCLUDED
+#define SQL_CALLBACK_INCLUDED
+
+/**
+ Macro used for an internal callback.
+
+ The macro will check that the object exists and that the function
+ is defined. If that is the case, it will call the function with the
+ given parameters.
+
+ If the object or the function is not defined, the callback will be
+ considered successful (nothing needed to be done) and will
+ therefore return no error.
+ */
+
+#define MYSQL_CALLBACK(OBJ, FUNC, PARAMS) \
+ do { \
+ if ((OBJ) && ((OBJ)->FUNC)) \
+ (OBJ)->FUNC PARAMS; \
+ } while (0)
+
+#define MYSQL_CALLBACK_ELSE(OBJ, FUNC, PARAMS, ELSE) \
+ (((OBJ) && ((OBJ)->FUNC)) ? (OBJ)->FUNC PARAMS : (ELSE))
+
+
+#endif /* SQL_CALLBACK_INCLUDED */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index bde56777d52..f65e5c05826 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -57,6 +57,7 @@
#include "transaction.h"
#include "debug_sync.h"
#include "sql_parse.h" // is_update_query
+#include "sql_callback.h"
/*
The following is used to initialise Table_ident with a internal
@@ -1075,6 +1076,7 @@ THD::~THD()
DBUG_ENTER("~THD()");
/* Ensure that no one is using THD */
mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_unlock(&LOCK_thd_data);
add_to_status(&global_status_var, &status_var);
@@ -1100,7 +1102,6 @@ THD::~THD()
my_free(db);
db= NULL;
free_root(&transaction.mem_root,MYF(0));
- mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_destroy(&LOCK_thd_data);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
@@ -1189,7 +1190,7 @@ void THD::awake(THD::killed_state state_to_set)
{
thr_alarm_kill(thread_id);
if (!slave_thread)
- thread_scheduler.post_kill_notification(this);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (this));
#ifdef SIGNAL_WITH_VIO_CLOSE
if (this != current_thd)
{
@@ -1258,6 +1259,15 @@ bool THD::store_globals()
if (my_pthread_setspecific_ptr(THR_THD, this) ||
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
+ /*
+ mysys_var is concurrently readable by a killer thread.
+ It is protected by LOCK_thd_data, it is not needed to lock while the
+ pointer is changing from NULL not non-NULL. If the kill thread reads
+ NULL it doesn't refer to anything, but if it is non-NULL we need to
+ ensure that the thread doesn't proceed to assign another thread to
+ have the mysys_var reference (which in fact refers to the worker
+ threads local storage with key THR_KEY_mysys.
+ */
mysys_var=my_thread_var;
/*
Let mysqld define the thread id (not mysys)
@@ -3187,6 +3197,60 @@ extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
{
return sqlcom_can_generate_row_events(thd);
}
+
+#ifndef EMBEDDED_LIBRARY
+extern "C" void thd_pool_wait_begin(MYSQL_THD thd, int wait_type);
+extern "C" void thd_pool_wait_end(MYSQL_THD thd);
+
+/*
+ Interface for MySQL Server, plugins and storage engines to report
+ when they are going to sleep/stall.
+
+ SYNOPSIS
+ thd_wait_begin()
+ thd Thread object
+ wait_type Type of wait
+ 1 -- short wait (e.g. for mutex)
+ 2 -- medium wait (e.g. for disk io)
+ 3 -- large wait (e.g. for locked row/table)
+ NOTES
+ This is used by the threadpool to have better knowledge of which
+ threads that currently are actively running on CPUs. When a thread
+ reports that it's going to sleep/stall, the threadpool scheduler is
+ free to start another thread in the pool most likely. The expected wait
+ time is simply an indication of how long the wait is expected to
+ become, the real wait time could be very different.
+
+ thd_wait_end MUST be called immediately after waking up again.
+*/
+extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type));
+}
+
+/**
+ Interface for MySQL Server, plugins and storage engines to report
+ when they waking up from a sleep/stall.
+
+ @param thd Thread handle
+*/
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd));
+}
+#else
+extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+#endif
#endif // INNODB_COMPATIBILITY_HOOKS */
/****************************************************************************
@@ -3370,6 +3434,13 @@ void THD::set_query_id(query_id_t new_query_id)
mysql_mutex_unlock(&LOCK_thd_data);
}
+/** Assign a new value to thd->mysys_var. */
+void THD::set_mysys_var(struct st_my_thread_var *new_mysys_var)
+{
+ mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var= new_mysys_var;
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
/**
Leave explicit LOCK TABLES or prelocked mode and restore value of
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 462fbf9a264..e86e42dc094 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1634,6 +1634,10 @@ public:
xid_state.xid.null();
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
}
+ my_bool is_active()
+ {
+ return (all.ha_list != NULL);
+ }
st_transactions()
{
bzero((char*)this, sizeof(*this));
@@ -2664,7 +2668,7 @@ public:
virtual void set_statement(Statement *stmt);
/**
- Assign a new value to thd->query and thd->query_id.
+ Assign a new value to thd->query and thd->query_id and mysys_var.
Protected with LOCK_thd_data mutex.
*/
void set_query(char *query_arg, uint32 query_length_arg);
@@ -2677,6 +2681,7 @@ public:
open_tables= open_tables_arg;
mysql_mutex_unlock(&LOCK_thd_data);
}
+ void set_mysys_var(struct st_my_thread_var *new_mysys_var);
void enter_locked_tables_mode(enum_locked_tables_mode mode_arg)
{
DBUG_ASSERT(locked_tables_mode == LTM_NONE);
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 003203b5466..3ba6deed0a4 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -35,6 +35,7 @@
#include "hostname.h" // inc_host_errors, ip_to_hostname,
// reset_host_errors
#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
+#include "sql_callback.h"
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
/*
@@ -966,7 +967,7 @@ bool setup_connection_thread_globals(THD *thd)
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd, 0);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
return 1; // Error
}
return 0;
@@ -989,7 +990,7 @@ bool setup_connection_thread_globals(THD *thd)
*/
-static bool login_connection(THD *thd)
+bool login_connection(THD *thd)
{
NET *net= &thd->net;
int error;
@@ -1027,7 +1028,7 @@ static bool login_connection(THD *thd)
This mainly updates status variables
*/
-static void end_connection(THD *thd)
+void end_connection(THD *thd)
{
NET *net= &thd->net;
plugin_thdvar_cleanup(thd);
@@ -1068,7 +1069,7 @@ static void end_connection(THD *thd)
Initialize THD to handle queries
*/
-static void prepare_new_connection_state(THD* thd)
+void prepare_new_connection_state(THD* thd)
{
Security_context *sctx= thd->security_ctx;
@@ -1137,11 +1138,11 @@ void do_handle_one_connection(THD *thd_arg)
thd->thr_create_utime= my_micro_time();
- if (thread_scheduler.init_new_connection_thread())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd,0);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
return;
}
@@ -1195,7 +1196,7 @@ void do_handle_one_connection(THD *thd_arg)
end_thread:
close_connection(thd, 0, 1);
- if (thread_scheduler.end_thread(thd,1))
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
return; // Probably no-threads
/*
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index 2334b7303be..bfcc04ba093 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -40,4 +40,8 @@ int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count);
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+
#endif /* SQL_CONNECT_INCLUDED */
diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h
index 7491ddab79d..f39e22f1e21 100644
--- a/sql/sql_plugin_services.h
+++ b/sql/sql_plugin_services.h
@@ -36,9 +36,23 @@ static struct thd_alloc_service_st thd_alloc_handler= {
thd_make_lex_string
};
+static struct thd_wait_service_st thd_wait_handler= {
+ thd_wait_begin,
+ thd_wait_end
+};
+
+static struct my_thread_scheduler_service my_thread_scheduler_handler= {
+ my_thread_scheduler_set,
+ my_thread_scheduler_reset,
+};
+
+
static struct st_service_ref list_of_services[]=
{
{ "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
- { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler }
+ { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler },
+ { "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
+ { "my_thread_scheduler_service",
+ VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
};
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3c9eb215641..29a78cb31dc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -12723,7 +12723,9 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!end_of_records)
{
copy_fields(&join->tmp_table_param);
- copy_funcs(join->tmp_table_param.items_to_copy);
+ if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
+
if (!join->having || join->having->val_int())
{
int error;
@@ -12813,7 +12815,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
memcpy(table->record[0]+key_part->offset, group->buff, 1);
}
init_tmptable_sum_functions(join->sum_funcs);
- copy_funcs(join->tmp_table_param.items_to_copy);
+ if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if ((error=table->file->ha_write_row(table->record[0])))
{
if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
@@ -12848,7 +12851,8 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
init_tmptable_sum_functions(join->sum_funcs);
copy_fields(&join->tmp_table_param); // Groups are copied twice.
- copy_funcs(join->tmp_table_param.items_to_copy);
+ if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (!(error=table->file->ha_write_row(table->record[0])))
join->send_records++; // New group
@@ -12935,7 +12939,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (idx < (int) join->send_group_parts)
{
copy_fields(&join->tmp_table_param);
- copy_funcs(join->tmp_table_param.items_to_copy);
+ if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
+ DBUG_RETURN(NESTED_LOOP_ERROR);
if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
DBUG_RETURN(NESTED_LOOP_ERROR);
if (join->procedure)
@@ -13238,6 +13243,34 @@ ok:
}
+/**
+ Find shortest key suitable for full table scan.
+
+ @param table Table to scan
+ @param usable_keys Allowed keys
+
+ @note
+ As far as
+ 1) clustered primary key entry data set is a set of all record
+ fields (key fields and not key fields) and
+ 2) secondary index entry data is a union of its key fields and
+ primary key fields (at least InnoDB and its derivatives don't
+ duplicate primary key fields there, even if the primary and
+ the secondary keys have a common subset of key fields),
+ then secondary index entry data is always a subset of primary key entry.
+ Unfortunately, key_info[nr].key_length doesn't show the length
+ of key/pointer pair but a sum of key field lengths only, thus
+ we can't estimate index IO volume comparing only this key_length
+ value of secondary keys and clustered PK.
+ So, try secondary keys first, and choose PK only if there are no
+ usable secondary covering keys or found best secondary key include
+ all table fields (i.e. same as PK):
+
+ @return
+ MAX_KEY no suitable key found
+ key index otherwise
+*/
+
uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
uint best= MAX_KEY;
@@ -13250,23 +13283,6 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
uint min_length= (uint) ~0;
for (uint nr=0; nr < table->s->keys ; nr++)
{
- /*
- As far as
- 1) clustered primary key entry data set is a set of all record
- fields (key fields and not key fields) and
- 2) secondary index entry data is a union of its key fields and
- primary key fields (at least InnoDB and its derivatives don't
- duplicate primary key fields there, even if the primary and
- the secondary keys have a common subset of key fields),
- then secondary index entry data is always a subset of primary key
- entry, and the PK is always longer.
- Unfortunately, key_info[nr].key_length doesn't show the length
- of key/pointer pair but a sum of key field lengths only, thus
- we can't estimate index IO volume comparing only this key_length
- value of seconday keys and clustered PK.
- So, try secondary keys first, and choose PK only if there are no
- usable secondary covering keys:
- */
if (nr == usable_clustered_pk)
continue;
if (usable_keys->is_set(nr))
@@ -13279,7 +13295,20 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
}
}
}
- return best != MAX_KEY ? best : usable_clustered_pk;
+ if (usable_clustered_pk != MAX_KEY)
+ {
+ /*
+ If the primary key is clustered and found shorter key covers all table
+ fields then primary key scan normally would be faster because amount of
+ data to scan is the same but PK is clustered.
+ It's safe to compare key parts with table fields since duplicate key
+ parts aren't allowed.
+ */
+ if (best == MAX_KEY ||
+ table->key_info[best].key_parts >= table->s->fields)
+ best= usable_clustered_pk;
+ }
+ return best;
}
/**
@@ -15807,14 +15836,39 @@ update_sum_func(Item_sum **func_ptr)
return 0;
}
-/** Copy result of functions to record in tmp_table. */
+/**
+ Copy result of functions to record in tmp_table.
-void
-copy_funcs(Item **func_ptr)
+ Uses the thread pointer to check for errors in
+ some of the val_xxx() methods called by the
+ save_in_result_field() function.
+ TODO: make the Item::val_xxx() return error code
+
+ @param func_ptr array of the function Items to copy to the tmp table
+ @param thd pointer to the current thread for error checking
+ @retval
+ FALSE if OK
+ @retval
+ TRUE on error
+*/
+
+bool
+copy_funcs(Item **func_ptr, const THD *thd)
{
Item *func;
for (; (func = *func_ptr) ; func_ptr++)
+ {
func->save_in_result_field(1);
+ /*
+ Need to check the THD error state because Item::val_xxx() don't
+ return error code, but can generate errors
+ TODO: change it for a real status check when Item::val_xxx()
+ are extended to return status code.
+ */
+ if (thd->is_error())
+ return TRUE;
+ }
+ return FALSE;
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 40f9e6d4054..77fff4ee24c 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -606,7 +606,7 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
List<Item> &new_list1, List<Item> &new_list2,
uint elements, List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
-void copy_funcs(Item **func_ptr);
+bool copy_funcs(Item **func_ptr, const THD *thd);
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int error, bool ignore_last_dupp_error);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 3f0c0b9eaf9..6b24e3db7bc 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1815,6 +1815,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command;
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
@@ -1822,16 +1823,15 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
- thd_info->start_time= tmp->start_time;
thd_info->query=0;
/* Lock THD mutex that protects its data when looking at it. */
- mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query())
{
uint length= min(max_query_length, tmp->query_length());
thd_info->query= (char*) thd->strmake(tmp->query(),length);
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ thd_info->start_time= tmp->start_time;
thread_infos.append(thd_info);
}
}
@@ -1918,6 +1918,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[3]->set_notnull();
}
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
/* COMMAND */
@@ -1938,6 +1939,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
/* INFO */
/* Lock THD mutex that protects its data when looking at it. */
@@ -7490,13 +7492,16 @@ int finalize_schema_table(st_plugin_int *plugin)
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("finalize_schema_table");
- if (schema_table && plugin->plugin->deinit)
+ if (schema_table)
{
- DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
- if (plugin->plugin->deinit(NULL))
+ if (plugin->plugin->deinit)
{
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
+ DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
+ if (plugin->plugin->deinit(NULL))
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ plugin->name.str));
+ }
}
my_free(schema_table);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2b2f9808c71..83e9078f5cb 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1425,6 +1425,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <table>
table_ident table_ident_nodb references xid
+ table_ident_opt_wild
%type <simple_string>
remember_name remember_end opt_db text_or_password
@@ -10371,7 +10372,7 @@ table_alias_ref_list:
;
table_alias_ref:
- table_ident
+ table_ident_opt_wild
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
@@ -12161,6 +12162,21 @@ table_ident:
}
;
+table_ident_opt_wild:
+ ident opt_wild
+ {
+ $$= new Table_ident($1);
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
+ | ident '.' ident opt_wild
+ {
+ $$= new Table_ident(YYTHD, $1,$3,0);
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
+ ;
+
table_ident_nodb:
ident
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index f63a43ccd76..ca3447dcc82 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1673,19 +1673,13 @@ static Sys_var_ulong Sys_trans_prealloc_size(
static const char *thread_handling_names[]=
{
- "one-thread-per-connection", "no-threads",
-#if HAVE_POOL_OF_THREADS == 1
- "pool-of-threads",
-#endif
+ "one-thread-per-connection", "no-threads", "loaded-dynamically",
0
};
static Sys_var_enum Sys_thread_handling(
"thread_handling",
"Define threads usage for handling queries, one of "
- "one-thread-per-connection, no-threads"
-#if HAVE_POOL_OF_THREADS == 1
- ", pool-of-threads"
-#endif
+ "one-thread-per-connection, no-threads, loaded-dynamically"
, READ_ONLY GLOBAL_VAR(thread_handling), CMD_LINE(REQUIRED_ARG),
thread_handling_names, DEFAULT(0));
diff --git a/sql/table.h b/sql/table.h
index ea93b321b5a..6723293c1ec 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -192,7 +192,6 @@ typedef struct st_order {
struct st_order *next;
Item **item; /* Point at item in select fields */
Item *item_ptr; /* Storage for initial item */
- Item **item_copy; /* For SPs; the original item ptr */
int counter; /* position in SELECT list, correct
only if counter_used is true*/
bool asc; /* true if ascending */