mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Auto-merged.
This commit is contained in:
commit
a5ffc6faf5
86 changed files with 1380 additions and 364 deletions
|
@ -248,10 +248,14 @@ struct st_connection
|
|||
my_bool pending;
|
||||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
pthread_t tid;
|
||||
const char *cur_query;
|
||||
int cur_query_len;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int command, result;
|
||||
pthread_mutex_t query_mutex;
|
||||
pthread_cond_t query_cond;
|
||||
pthread_mutex_t result_mutex;
|
||||
pthread_cond_t result_cond;
|
||||
int query_done;
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
};
|
||||
|
@ -703,67 +707,148 @@ void handle_no_error(struct st_command*);
|
|||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
|
||||
#define EMB_SEND_QUERY 1
|
||||
#define EMB_READ_QUERY_RESULT 2
|
||||
#define EMB_END_CONNECTION 3
|
||||
|
||||
/* attributes of the query thread */
|
||||
pthread_attr_t cn_thd_attrib;
|
||||
|
||||
|
||||
/*
|
||||
send_one_query executes query in separate thread, which is
|
||||
necessary in embedded library to run 'send' in proper way.
|
||||
This implementation doesn't handle errors returned
|
||||
by mysql_send_query. It's technically possible, though
|
||||
I don't see where it is needed.
|
||||
This procedure represents the connection and actually
|
||||
runs queries when in the EMBEDDED-SERVER mode.
|
||||
The run_query_normal() just sends request for running
|
||||
mysql_send_query and mysql_read_query_result() here.
|
||||
*/
|
||||
pthread_handler_t send_one_query(void *arg)
|
||||
|
||||
pthread_handler_t connection_thread(void *arg)
|
||||
{
|
||||
struct st_connection *cn= (struct st_connection*)arg;
|
||||
|
||||
mysql_thread_init();
|
||||
(void) mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len);
|
||||
while (cn->command != EMB_END_CONNECTION)
|
||||
{
|
||||
if (!cn->command)
|
||||
{
|
||||
pthread_mutex_lock(&cn->query_mutex);
|
||||
while (!cn->command)
|
||||
pthread_cond_wait(&cn->query_cond, &cn->query_mutex);
|
||||
pthread_mutex_unlock(&cn->query_mutex);
|
||||
}
|
||||
switch (cn->command)
|
||||
{
|
||||
case EMB_END_CONNECTION:
|
||||
goto end_thread;
|
||||
case EMB_SEND_QUERY:
|
||||
cn->result= mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len);
|
||||
break;
|
||||
case EMB_READ_QUERY_RESULT:
|
||||
cn->result= mysql_read_query_result(&cn->mysql);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
cn->command= 0;
|
||||
pthread_mutex_lock(&cn->result_mutex);
|
||||
cn->query_done= 1;
|
||||
pthread_cond_signal(&cn->result_cond);
|
||||
pthread_mutex_unlock(&cn->result_mutex);
|
||||
}
|
||||
|
||||
mysql_thread_end();
|
||||
pthread_mutex_lock(&cn->mutex);
|
||||
end_thread:
|
||||
cn->query_done= 1;
|
||||
pthread_cond_signal(&cn->cond);
|
||||
pthread_mutex_unlock(&cn->mutex);
|
||||
mysql_thread_end();
|
||||
pthread_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_send_query(struct st_connection *cn, const char *q, int q_len,
|
||||
int flags)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
if (flags & QUERY_REAP_FLAG)
|
||||
return mysql_send_query(&cn->mysql, q, q_len);
|
||||
|
||||
if (pthread_mutex_init(&cn->mutex, NULL) ||
|
||||
pthread_cond_init(&cn->cond, NULL))
|
||||
die("Error in the thread library");
|
||||
|
||||
cn->cur_query= q;
|
||||
cn->cur_query_len= q_len;
|
||||
cn->query_done= 0;
|
||||
if (pthread_create(&tid, &cn_thd_attrib, send_one_query, (void*)cn))
|
||||
die("Cannot start new thread for query");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_query_thread_end(struct st_connection *con)
|
||||
|
||||
static void wait_query_thread_done(struct st_connection *con)
|
||||
{
|
||||
DBUG_ASSERT(con->tid);
|
||||
if (!con->query_done)
|
||||
{
|
||||
pthread_mutex_lock(&con->mutex);
|
||||
pthread_mutex_lock(&con->result_mutex);
|
||||
while (!con->query_done)
|
||||
pthread_cond_wait(&con->cond, &con->mutex);
|
||||
pthread_mutex_unlock(&con->mutex);
|
||||
pthread_cond_wait(&con->result_cond, &con->result_mutex);
|
||||
pthread_mutex_unlock(&con->result_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void signal_connection_thd(struct st_connection *cn, int command)
|
||||
{
|
||||
DBUG_ASSERT(cn->tid);
|
||||
cn->query_done= 0;
|
||||
cn->command= command;
|
||||
pthread_mutex_lock(&cn->query_mutex);
|
||||
pthread_cond_signal(&cn->query_cond);
|
||||
pthread_mutex_unlock(&cn->query_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Sometimes we try to execute queries when the connection is closed.
|
||||
It's done to make sure it was closed completely.
|
||||
So that if our connection is closed (cn->tid == 0), we just return
|
||||
the mysql_send_query() result which is an error in this case.
|
||||
*/
|
||||
|
||||
static int do_send_query(struct st_connection *cn, const char *q, int q_len)
|
||||
{
|
||||
if (!cn->tid)
|
||||
return mysql_send_query(&cn->mysql, q, q_len);
|
||||
cn->cur_query= q;
|
||||
cn->cur_query_len= q_len;
|
||||
signal_connection_thd(cn, EMB_SEND_QUERY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int do_read_query_result(struct st_connection *cn)
|
||||
{
|
||||
DBUG_ASSERT(cn->tid);
|
||||
wait_query_thread_done(cn);
|
||||
signal_connection_thd(cn, EMB_READ_QUERY_RESULT);
|
||||
wait_query_thread_done(cn);
|
||||
|
||||
return cn->result;
|
||||
}
|
||||
|
||||
|
||||
static void emb_close_connection(struct st_connection *cn)
|
||||
{
|
||||
if (!cn->tid)
|
||||
return;
|
||||
wait_query_thread_done(cn);
|
||||
signal_connection_thd(cn, EMB_END_CONNECTION);
|
||||
pthread_join(cn->tid, NULL);
|
||||
cn->tid= 0;
|
||||
pthread_mutex_destroy(&cn->query_mutex);
|
||||
pthread_cond_destroy(&cn->query_cond);
|
||||
pthread_mutex_destroy(&cn->result_mutex);
|
||||
pthread_cond_destroy(&cn->result_cond);
|
||||
}
|
||||
|
||||
|
||||
static void init_connection_thd(struct st_connection *cn)
|
||||
{
|
||||
cn->query_done= 1;
|
||||
cn->command= 0;
|
||||
if (pthread_mutex_init(&cn->query_mutex, NULL) ||
|
||||
pthread_cond_init(&cn->query_cond, NULL) ||
|
||||
pthread_mutex_init(&cn->result_mutex, NULL) ||
|
||||
pthread_cond_init(&cn->result_cond, NULL) ||
|
||||
pthread_create(&cn->tid, &cn_thd_attrib, connection_thread, (void*)cn))
|
||||
die("Error in the thread library");
|
||||
}
|
||||
|
||||
|
||||
#else /*EMBEDDED_LIBRARY*/
|
||||
|
||||
#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len)
|
||||
#define do_send_query(cn,q,q_len) mysql_send_query(&cn->mysql, q, q_len)
|
||||
#define do_read_query_result(cn) mysql_read_query_result(&cn->mysql)
|
||||
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
|
||||
|
@ -1106,6 +1191,9 @@ void close_connections()
|
|||
DBUG_ENTER("close_connections");
|
||||
for (--next_con; next_con >= connections; --next_con)
|
||||
{
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
emb_close_connection(next_con);
|
||||
#endif
|
||||
if (next_con->stmt)
|
||||
mysql_stmt_close(next_con->stmt);
|
||||
next_con->stmt= 0;
|
||||
|
@ -4866,7 +4954,7 @@ void do_close_connection(struct st_command *command)
|
|||
we need to check if the query's thread was finished and probably wait
|
||||
(embedded-server specific)
|
||||
*/
|
||||
wait_query_thread_end(con);
|
||||
emb_close_connection(con);
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
if (con->stmt)
|
||||
mysql_stmt_close(con->stmt);
|
||||
|
@ -5216,8 +5304,9 @@ void do_connect(struct st_command *command)
|
|||
}
|
||||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
con_slot->query_done= 1;
|
||||
#endif
|
||||
init_connection_thd(con_slot);
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
|
||||
if (!mysql_init(&con_slot->mysql))
|
||||
die("Failed on mysql_init()");
|
||||
|
||||
|
@ -6228,8 +6317,10 @@ get_one_option(int optid, const struct my_option *opt, char *argument)
|
|||
print_version();
|
||||
exit(0);
|
||||
case OPT_MYSQL_PROTOCOL:
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
|
||||
opt->name);
|
||||
#endif
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
|
@ -6766,21 +6857,13 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
|
|||
/*
|
||||
Send the query
|
||||
*/
|
||||
if (do_send_query(cn, query, query_len, flags))
|
||||
if (do_send_query(cn, query, query_len))
|
||||
{
|
||||
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
||||
mysql_sqlstate(mysql), ds);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
/*
|
||||
Here we handle 'reap' command, so we need to check if the
|
||||
query's thread was finished and probably wait
|
||||
*/
|
||||
else if (flags & QUERY_REAP_FLAG)
|
||||
wait_query_thread_end(cn);
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
if (!(flags & QUERY_REAP_FLAG))
|
||||
{
|
||||
cn->pending= TRUE;
|
||||
|
@ -6793,7 +6876,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
|
|||
When on first result set, call mysql_read_query_result to retrieve
|
||||
answer to the query sent earlier
|
||||
*/
|
||||
if ((counter==0) && mysql_read_query_result(mysql))
|
||||
if ((counter==0) && do_read_query_result(cn))
|
||||
{
|
||||
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
||||
mysql_sqlstate(mysql), ds);
|
||||
|
@ -7968,6 +8051,9 @@ int main(int argc, char **argv)
|
|||
ps_protocol_enabled= 1;
|
||||
|
||||
st_connection *con= connections;
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
init_connection_thd(con);
|
||||
#endif /*EMBEDDED_LIBRARY*/
|
||||
if (!( mysql_init(&con->mysql)))
|
||||
die("Failed in mysql_init()");
|
||||
if (opt_connect_timeout)
|
||||
|
|
|
@ -13,13 +13,30 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCXX
|
||||
AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
IF(NOT DEFINED BUGGY_GCC_NO_DTRACE_MODULES)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1} --version
|
||||
OUTPUT_VARIABLE out)
|
||||
IF(out MATCHES "3.4.6")
|
||||
# This gcc causes crashes in dlopen() for dtraced shared libs,
|
||||
# while standard shipped with Solaris10 3.4.3 is ok
|
||||
SET(BUGGY_GCC_NO_DTRACE_MODULES 1 CACHE INTERNAL "")
|
||||
ELSE()
|
||||
SET(BUGGY_GCC_NO_DTRACE_MODULES 0 CACHE INTERNAL "")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
# Check if OS supports DTrace
|
||||
MACRO(CHECK_DTRACE)
|
||||
FIND_PROGRAM(DTRACE dtrace)
|
||||
MARK_AS_ADVANCED(DTRACE)
|
||||
|
||||
# On FreeBSD, dtrace does not handle userland tracing yet
|
||||
IF(DTRACE AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
IF(DTRACE AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD"
|
||||
AND NOT BUGGY_GCC_NO_DTRACE_MODULES)
|
||||
SET(ENABLE_DTRACE ON CACHE BOOL "Enable dtrace")
|
||||
ENDIF()
|
||||
SET(HAVE_DTRACE ${ENABLE_DTRACE})
|
||||
|
@ -72,22 +89,6 @@ IF(ENABLE_DTRACE)
|
|||
)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCXX
|
||||
AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
IF(NOT DEFINED BUGGY_GCC_NO_DTRACE_MODULES)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1} --version
|
||||
OUTPUT_VARIABLE out)
|
||||
IF(out MATCHES "3.4.6")
|
||||
# This gcc causes crashes in dlopen() for dtraced shared libs,
|
||||
# while standard shipped with Solaris10 3.4.3 is ok
|
||||
SET(BUGGY_GCC_NO_DTRACE_MODULES 1 CACHE INTERNAL "")
|
||||
ELSE()
|
||||
SET(BUGGY_GCC_NO_DTRACE_MODULES 0 CACHE INTERNAL "")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
FUNCTION(DTRACE_INSTRUMENT target)
|
||||
IF(BUGGY_GCC_NO_DTRACE_MODULES)
|
||||
GET_TARGET_PROPERTY(target_type ${target} TYPE)
|
||||
|
|
|
@ -27,7 +27,7 @@ dnl
|
|||
dnl When changing the major version number please also check the switch
|
||||
dnl statement in mysqlbinlog::check_master_version(). You may also need
|
||||
dnl to update version.c in ndb.
|
||||
AC_INIT([MySQL Server], [5.5.6-m3], [], [mysql])
|
||||
AC_INIT([MySQL Server], [5.5.7-m3], [], [mysql])
|
||||
|
||||
AC_CONFIG_SRCDIR([sql/mysqld.cc])
|
||||
AC_CANONICAL_SYSTEM
|
||||
|
|
|
@ -26,6 +26,8 @@ HEADERS_ABI = mysql.h mysql_com.h mysql_time.h \
|
|||
pkginclude_HEADERS = $(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
|
||||
my_xml.h mysql_embed.h mysql/services.h \
|
||||
mysql/service_my_snprintf.h mysql/service_thd_alloc.h \
|
||||
mysql/service_thread_scheduler.h \
|
||||
mysql/service_thd_wait.h \
|
||||
my_pthread.h my_no_pthread.h \
|
||||
decimal.h errmsg.h my_global.h my_net.h \
|
||||
my_getopt.h sslopt-longopts.h my_dir.h \
|
||||
|
|
|
@ -71,7 +71,7 @@ typedef struct st_mysql_xid MYSQL_XID;
|
|||
Plugin API. Common for all plugin types.
|
||||
*/
|
||||
|
||||
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0101
|
||||
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102
|
||||
|
||||
/*
|
||||
The allowable types of plugins
|
||||
|
|
|
@ -31,6 +31,27 @@ void *thd_memdup(void* thd, const void* str, unsigned int size);
|
|||
MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
|
||||
const char *str, unsigned int size,
|
||||
int allocate_lex_string);
|
||||
#include <mysql/service_thd_wait.h>
|
||||
typedef enum _thd_wait_type_e {
|
||||
THD_WAIT_MUTEX= 1,
|
||||
THD_WAIT_DISKIO= 2,
|
||||
THD_WAIT_ROW_TABLE_LOCK= 3,
|
||||
THD_WAIT_GLOBAL_LOCK= 4
|
||||
} thd_wait_type;
|
||||
extern struct thd_wait_service_st {
|
||||
void (*thd_wait_begin_func)(void*, thd_wait_type);
|
||||
void (*thd_wait_end_func)(void*);
|
||||
} *thd_wait_service;
|
||||
void thd_wait_begin(void* thd, thd_wait_type wait_type);
|
||||
void thd_wait_end(void* thd);
|
||||
#include <mysql/service_thread_scheduler.h>
|
||||
struct scheduler_functions;
|
||||
extern struct my_thread_scheduler_service {
|
||||
int (*set)(struct scheduler_functions *scheduler);
|
||||
int (*reset)();
|
||||
} *my_thread_scheduler_service;
|
||||
int my_thread_scheduler_set(struct scheduler_functions *scheduler);
|
||||
int my_thread_scheduler_reset();
|
||||
struct st_mysql_xid {
|
||||
long formatID;
|
||||
long gtrid_length;
|
||||
|
|
|
@ -31,6 +31,27 @@ void *thd_memdup(void* thd, const void* str, unsigned int size);
|
|||
MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
|
||||
const char *str, unsigned int size,
|
||||
int allocate_lex_string);
|
||||
#include <mysql/service_thd_wait.h>
|
||||
typedef enum _thd_wait_type_e {
|
||||
THD_WAIT_MUTEX= 1,
|
||||
THD_WAIT_DISKIO= 2,
|
||||
THD_WAIT_ROW_TABLE_LOCK= 3,
|
||||
THD_WAIT_GLOBAL_LOCK= 4
|
||||
} thd_wait_type;
|
||||
extern struct thd_wait_service_st {
|
||||
void (*thd_wait_begin_func)(void*, thd_wait_type);
|
||||
void (*thd_wait_end_func)(void*);
|
||||
} *thd_wait_service;
|
||||
void thd_wait_begin(void* thd, thd_wait_type wait_type);
|
||||
void thd_wait_end(void* thd);
|
||||
#include <mysql/service_thread_scheduler.h>
|
||||
struct scheduler_functions;
|
||||
extern struct my_thread_scheduler_service {
|
||||
int (*set)(struct scheduler_functions *scheduler);
|
||||
int (*reset)();
|
||||
} *my_thread_scheduler_service;
|
||||
int my_thread_scheduler_set(struct scheduler_functions *scheduler);
|
||||
int my_thread_scheduler_reset();
|
||||
struct st_mysql_xid {
|
||||
long formatID;
|
||||
long gtrid_length;
|
||||
|
|
83
include/mysql/service_thd_wait.h
Normal file
83
include/mysql/service_thd_wait.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* 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 MYSQL_SERVICE_THD_WAIT_INCLUDED
|
||||
#define MYSQL_SERVICE_THD_WAIT_INCLUDED
|
||||
|
||||
/**
|
||||
@file include/mysql/service_thd_wait.h
|
||||
This service provides functions for plugins and storage engines to report
|
||||
when they are going to sleep/stall.
|
||||
|
||||
SYNOPSIS
|
||||
thd_wait_begin() - call just before a wait begins
|
||||
thd Thread object
|
||||
Use NULL if the thd is NOT known.
|
||||
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() called immediately after the wait is complete
|
||||
|
||||
thd_wait_end() MUST be called if thd_wait_begin() was called.
|
||||
|
||||
Using thd_wait_...() service is optional but recommended. Using it will
|
||||
improve performance as the thread pool will be more active at managing the
|
||||
thread workload.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum _thd_wait_type_e {
|
||||
THD_WAIT_MUTEX= 1,
|
||||
THD_WAIT_DISKIO= 2,
|
||||
THD_WAIT_ROW_TABLE_LOCK= 3,
|
||||
THD_WAIT_GLOBAL_LOCK= 4
|
||||
} thd_wait_type;
|
||||
|
||||
extern struct thd_wait_service_st {
|
||||
void (*thd_wait_begin_func)(MYSQL_THD, thd_wait_type);
|
||||
void (*thd_wait_end_func)(MYSQL_THD);
|
||||
} *thd_wait_service;
|
||||
|
||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||
|
||||
#define thd_wait_begin(_THD, _WAIT_TYPE) \
|
||||
thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE)
|
||||
#define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD)
|
||||
|
||||
#else
|
||||
|
||||
void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type);
|
||||
void thd_wait_end(MYSQL_THD thd);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
65
include/mysql/service_thread_scheduler.h
Normal file
65
include/mysql/service_thread_scheduler.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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 SERVICE_THREAD_SCHEDULER_INCLUDED
|
||||
#define SERVICE_THREAD_SCHEDULER_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct scheduler_functions;
|
||||
|
||||
extern struct my_thread_scheduler_service {
|
||||
int (*set)(struct scheduler_functions *scheduler);
|
||||
int (*reset)();
|
||||
} *my_thread_scheduler_service;
|
||||
|
||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||
|
||||
#define my_thread_scheduler_set(F) my_thread_scheduler_service->set((F))
|
||||
#define my_thread_scheduler_reset() my_thread_scheduler_service->reset()
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
Set the thread scheduler to use for the server.
|
||||
|
||||
@param scheduler Pointer to scheduler callbacks to use.
|
||||
@retval 0 Scheduler installed correctly.
|
||||
@retval 1 Invalid value (NULL) used for scheduler.
|
||||
*/
|
||||
int my_thread_scheduler_set(struct scheduler_functions *scheduler);
|
||||
|
||||
/**
|
||||
Restore the previous thread scheduler.
|
||||
|
||||
@note If no thread scheduler was installed previously with
|
||||
thd_set_thread_scheduler, this function will report an error.
|
||||
|
||||
@retval 0 Scheduler installed correctly.
|
||||
@retval 1 No scheduler installed.
|
||||
*/
|
||||
int my_thread_scheduler_reset();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SERVICE_THREAD_SCHEDULER_INCLUDED */
|
|
@ -20,6 +20,8 @@ extern "C" {
|
|||
|
||||
#include <mysql/service_my_snprintf.h>
|
||||
#include <mysql/service_thd_alloc.h>
|
||||
#include <mysql/service_thd_wait.h>
|
||||
#include <mysql/service_thread_scheduler.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -21,4 +21,5 @@
|
|||
|
||||
#define VERSION_my_snprintf 0x0100
|
||||
#define VERSION_thd_alloc 0x0100
|
||||
|
||||
#define VERSION_thd_wait 0x0100
|
||||
#define VERSION_my_thread_scheduler 0x0100
|
||||
|
|
|
@ -155,6 +155,8 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *data,
|
|||
enum thr_lock_type new_lock_type);
|
||||
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data,
|
||||
ulong lock_wait_timeout);
|
||||
void thr_set_lock_wait_callback(void (*before_wait)(void),
|
||||
void (*after_wait)(void));
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -217,6 +217,7 @@ struct st_vio
|
|||
void (*timeout)(Vio*, unsigned int which, unsigned int timeout);
|
||||
my_bool (*poll_read)(Vio *vio, uint timeout);
|
||||
my_bool (*is_connected)(Vio*);
|
||||
my_bool (*has_data) (Vio*);
|
||||
#ifdef HAVE_OPENSSL
|
||||
void *ssl_arg;
|
||||
#endif
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
# Copyright (C) 2001-2006 MySQL AB
|
||||
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; version 2
|
||||
# of the License.
|
||||
# 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 library is distributed in the hope that it will be useful,
|
||||
# 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
|
||||
# Library General Public License for more details.
|
||||
# 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 Library General Public
|
||||
# License along with this library; if not, write to the Free
|
||||
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
# MA 02111-1307, USA
|
||||
#
|
||||
# This file is public domain and comes with NO WARRANTY of any kind
|
||||
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
MYSQLDATAdir = $(localstatedir)
|
||||
MYSQLSHAREdir = $(pkgdatadir)
|
||||
|
|
|
@ -481,6 +481,10 @@ int init_embedded_server(int argc, char **argv, char **groups)
|
|||
char *fake_argv[] = { (char *)"", 0 };
|
||||
const char *fake_groups[] = { "server", "embedded", 0 };
|
||||
my_bool acl_error;
|
||||
|
||||
if (my_thread_init())
|
||||
return 1;
|
||||
|
||||
if (argc)
|
||||
{
|
||||
argcp= &argc;
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
SET(MYSQLSERVICES_SOURCES my_snprintf_service.c thd_alloc_service.c)
|
||||
SET(MYSQLSERVICES_SOURCES
|
||||
my_snprintf_service.c
|
||||
thd_alloc_service.c
|
||||
thd_wait_service.c
|
||||
my_thread_scheduler_service.c)
|
||||
|
||||
ADD_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
|
||||
INSTALL(TARGETS mysqlservices DESTINATION ${INSTALL_LIBDIR})
|
||||
|
|
|
@ -15,5 +15,7 @@
|
|||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
pkglib_LIBRARIES = libmysqlservices.a
|
||||
libmysqlservices_a_SOURCES = my_snprintf_service.c thd_alloc_service.c
|
||||
libmysqlservices_a_SOURCES = my_snprintf_service.c thd_alloc_service.c \
|
||||
thd_wait_service.c \
|
||||
my_thread_scheduler_service.c
|
||||
EXTRA_DIST = CMakeLists.txt
|
||||
|
|
21
libservices/my_thread_scheduler_service.c
Normal file
21
libservices/my_thread_scheduler_service.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#include <service_versions.h>
|
||||
SERVICE_VERSION my_thread_scheduler_service=
|
||||
(void*)VERSION_my_thread_scheduler;
|
19
libservices/thd_wait_service.c
Normal file
19
libservices/thd_wait_service.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#include <service_versions.h>
|
||||
SERVICE_VERSION *thd_wait_service= (void*)VERSION_thd_wait;
|
|
@ -13,6 +13,7 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
IF(INSTALL_MYSQLTESTDIR)
|
||||
INSTALL(
|
||||
DIRECTORY .
|
||||
DESTINATION ${INSTALL_MYSQLTESTDIR}
|
||||
|
@ -28,6 +29,7 @@ INSTALL(
|
|||
PATTERN "*.am" EXCLUDE
|
||||
PATTERN "*.in" EXCLUDE
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
||||
|
@ -48,9 +50,11 @@ IF(UNIX)
|
|||
./mysql-test-run.pl mysql-test-run
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mtr
|
||||
${CMAKE_CURRENT_BINARY_DIR}/mysql-test-run
|
||||
DESTINATION ${INSTALL_MYSQLTESTDIR})
|
||||
IF(INSTALL_MYSQLTESTDIR)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mtr
|
||||
${CMAKE_CURRENT_BINARY_DIR}/mysql-test-run
|
||||
DESTINATION ${INSTALL_MYSQLTESTDIR})
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
|
|
5
mysql-test/include/not_blackhole.inc
Normal file
5
mysql-test/include/not_blackhole.inc
Normal file
|
@ -0,0 +1,5 @@
|
|||
if (`SELECT count(*) FROM information_schema.engines WHERE
|
||||
(support = 'YES' OR support = 'DEFAULT') AND
|
||||
engine = 'blackhole'`){
|
||||
skip Blackhole engine enabled;
|
||||
}
|
|
@ -499,4 +499,13 @@ INDEX(a), INDEX(b), INDEX(c));
|
|||
INSERT INTO t1 VALUES (1,2,3), (4,5,6), (7,8,9);
|
||||
DELETE FROM t1 WHERE a = 10 OR b = 20 ORDER BY c LIMIT 1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug #53034: Multiple-table DELETE statements not accepting
|
||||
# "Access compatibility" syntax
|
||||
#
|
||||
CREATE TABLE t1 (id INT);
|
||||
CREATE TABLE t2 LIKE t1;
|
||||
CREATE TABLE t3 LIKE t1;
|
||||
DELETE FROM t1.*, test.t2.*, a.* USING t1, t2, t3 AS a;
|
||||
DROP TABLE t1, t2, t3;
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -1003,6 +1003,7 @@ SELECT 1 FROM
|
|||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests
|
||||
#
|
||||
# Bug #52397: another crash with explain extended and group_concat
|
||||
#
|
||||
|
@ -1019,6 +1020,25 @@ Warnings:
|
|||
Note 1003 select 1 AS `1` from dual
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests
|
||||
#
|
||||
# Bug #54476: crash when group_concat and 'with rollup' in prepared statements
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1), (2);
|
||||
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1.a ORDER BY t1.a) FROM t1 JOIN t1 t2 GROUP BY t1.a WITH ROLLUP";
|
||||
EXECUTE stmt;
|
||||
GROUP_CONCAT(t1.a ORDER BY t1.a)
|
||||
1,1
|
||||
2,2
|
||||
1,1,2,2
|
||||
EXECUTE stmt;
|
||||
GROUP_CONCAT(t1.a ORDER BY t1.a)
|
||||
1,1
|
||||
2,2
|
||||
1,1,2,2
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (a VARCHAR(6), b INT);
|
||||
CREATE TABLE t2 (a VARCHAR(6), b INT);
|
||||
|
|
|
@ -1713,6 +1713,17 @@ f1 f2 f3 f4 f1 = f2
|
|||
NULL NULL NULL NULL NULL
|
||||
drop table t1;
|
||||
#
|
||||
# Bug #54465: assert: field_types == 0 || field_types[field_pos] ==
|
||||
# MYSQL_TYPE_LONGLONG
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1), (2);
|
||||
SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1
|
||||
ORDER BY t1.a;
|
||||
m
|
||||
1
|
||||
DROP TABLE t1;
|
||||
#
|
||||
End of 5.1 tests
|
||||
#
|
||||
# Bug#55648: Server crash on MIN/MAX on maximum time value
|
||||
|
|
|
@ -337,6 +337,21 @@ select connection_id() > 0;
|
|||
connection_id() > 0
|
||||
1
|
||||
#
|
||||
# Bug #54461: crash with longblob and union or update with subquery
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b LONGBLOB);
|
||||
INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2');
|
||||
SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
|
||||
LEAST(a, (SELECT b FROM t1 LIMIT 1))
|
||||
1
|
||||
2
|
||||
SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
|
||||
GREATEST(a, (SELECT b FROM t1 LIMIT 1))
|
||||
2
|
||||
3
|
||||
1
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug #52165: Assertion failed: file .\dtoa.c, line 465
|
||||
#
|
||||
CREATE TABLE t1 (a SET('a'), b INT);
|
||||
|
|
|
@ -1307,4 +1307,12 @@ date_sub("0069-01-01 00:00:01",INTERVAL 2 SECOND)
|
|||
select date_sub("0169-01-01 00:00:01",INTERVAL 2 SECOND);
|
||||
date_sub("0169-01-01 00:00:01",INTERVAL 2 SECOND)
|
||||
0168-12-31 23:59:59
|
||||
CREATE TABLE t1(a DOUBLE NOT NULL);
|
||||
INSERT INTO t1 VALUES (0),(9.216e-096);
|
||||
# should not crash
|
||||
SELECT 1 FROM t1 ORDER BY @x:=makedate(a,a);
|
||||
1
|
||||
1
|
||||
1
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -688,7 +688,7 @@ The following options may be given as the first argument:
|
|||
How many threads we should keep in a cache for reuse
|
||||
--thread-handling=name
|
||||
Define threads usage for handling queries, one of
|
||||
one-thread-per-connection, no-threads
|
||||
one-thread-per-connection, no-threads, loaded-dynamically
|
||||
--thread-stack=# The stack size for each thread
|
||||
--time-format=name The TIME format (ignored)
|
||||
--timed-mutexes Specify whether to time mutexes (only InnoDB mutexes are
|
||||
|
|
|
@ -692,7 +692,7 @@ The following options may be given as the first argument:
|
|||
How many threads we should keep in a cache for reuse
|
||||
--thread-handling=name
|
||||
Define threads usage for handling queries, one of
|
||||
one-thread-per-connection, no-threads
|
||||
one-thread-per-connection, no-threads, loaded-dynamically
|
||||
--thread-stack=# The stack size for each thread
|
||||
--time-format=name The TIME format (ignored)
|
||||
--timed-mutexes Specify whether to time mutexes (only InnoDB mutexes are
|
||||
|
|
16
mysql-test/r/partition_not_blackhole.result
Normal file
16
mysql-test/r/partition_not_blackhole.result
Normal file
|
@ -0,0 +1,16 @@
|
|||
DROP TABLE IF EXISTS t1;
|
||||
#
|
||||
# Bug#46086: crash when dropping a partitioned table and
|
||||
# the original engine is disabled
|
||||
# Copy a .frm and .par file which was created with:
|
||||
# create table `t1` (`id` int primary key) engine=blackhole
|
||||
# partition by key () partitions 1;
|
||||
SHOW TABLES;
|
||||
Tables_in_test
|
||||
t1
|
||||
SHOW CREATE TABLE t1;
|
||||
ERROR HY000: Incorrect information in file: './test/t1.frm'
|
||||
DROP TABLE t1;
|
||||
ERROR 42S02: Unknown table 't1'
|
||||
t1.frm
|
||||
t1.par
|
|
@ -1653,4 +1653,17 @@ a b
|
|||
0 0
|
||||
1 1
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug #54802: 'NOT BETWEEN' evaluation is incorrect
|
||||
#
|
||||
CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
|
||||
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||
EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL c_key NULL NULL NULL 3 Using where
|
||||
SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
c_key c_notkey
|
||||
1 1
|
||||
3 3
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
|
|
BIN
mysql-test/std_data/parts/t1_blackhole.frm
Normal file
BIN
mysql-test/std_data/parts/t1_blackhole.frm
Normal file
Binary file not shown.
BIN
mysql-test/std_data/parts/t1_blackhole.par
Normal file
BIN
mysql-test/std_data/parts/t1_blackhole.par
Normal file
Binary file not shown.
|
@ -2549,6 +2549,64 @@ LOCK TABLES t1 READ;
|
|||
ALTER TABLE t1 COMMENT 'test';
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug#55656: mysqldump can be slower after bug #39653 fix
|
||||
#
|
||||
CREATE TABLE t1 (a INT , b INT, c INT, d INT,
|
||||
KEY (b), PRIMARY KEY (a,b)) ENGINE=INNODB;
|
||||
INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3);
|
||||
EXPLAIN SELECT COUNT(*) FROM t1;
|
||||
id 1
|
||||
select_type SIMPLE
|
||||
table t1
|
||||
type index
|
||||
possible_keys NULL
|
||||
key b
|
||||
key_len 4
|
||||
ref NULL
|
||||
rows 3
|
||||
Extra Using index
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b);
|
||||
EXPLAIN SELECT COUNT(*) FROM t1;
|
||||
id 1
|
||||
select_type SIMPLE
|
||||
table t1
|
||||
type index
|
||||
possible_keys NULL
|
||||
key b
|
||||
key_len 8
|
||||
ref NULL
|
||||
rows 3
|
||||
Extra Using index
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b,c);
|
||||
EXPLAIN SELECT COUNT(*) FROM t1;
|
||||
id 1
|
||||
select_type SIMPLE
|
||||
table t1
|
||||
type index
|
||||
possible_keys NULL
|
||||
key b
|
||||
key_len 13
|
||||
ref NULL
|
||||
rows 3
|
||||
Extra Using index
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b,c,d);
|
||||
EXPLAIN SELECT COUNT(*) FROM t1;
|
||||
id 1
|
||||
select_type SIMPLE
|
||||
table t1
|
||||
type index
|
||||
possible_keys NULL
|
||||
key PRIMARY
|
||||
key_len 8
|
||||
ref NULL
|
||||
rows 3
|
||||
Extra Using index
|
||||
DROP TABLE t1;
|
||||
#
|
||||
End of 5.1 tests
|
||||
#
|
||||
# Test for bug #39932 "create table fails if column for FK is in different
|
||||
|
|
|
@ -746,6 +746,31 @@ UNLOCK TABLES;
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#55656: mysqldump can be slower after bug #39653 fix
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT , b INT, c INT, d INT,
|
||||
KEY (b), PRIMARY KEY (a,b)) ENGINE=INNODB;
|
||||
INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3);
|
||||
--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
|
||||
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b);
|
||||
--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
|
||||
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b,c);
|
||||
--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
|
||||
|
||||
DROP INDEX b ON t1;
|
||||
CREATE INDEX b ON t1(a,b,c,d);
|
||||
--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
|
|
@ -4,12 +4,8 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
# Make sure the 'master_log.err-old' file does not
|
||||
# exist before execute 'flush error logs' statement.
|
||||
# Test if support 'flush error logs' statement.
|
||||
flush error logs;
|
||||
# Check the 'master_log.err-old' file is created
|
||||
# after executed 'flush error logs' statement.
|
||||
# Make sure binary logs was not be flushed
|
||||
# after execute 'flush error logs' statement.
|
||||
# Make sure relay logs was not be flushed
|
||||
|
@ -42,12 +38,8 @@ flush binary logs;
|
|||
# after executed 'flush binary logs' statement.
|
||||
# Make sure the 'slave-relay-bin.000007' file does not exist
|
||||
# exist before execute 'flush error logs, relay logs' statement.
|
||||
# Make sure the 'master_log.err-old' file does not exist
|
||||
# before execute 'flush error logs, relay logs' statement.
|
||||
# Test if support to combine all kinds of logs into one statement.
|
||||
flush error logs, relay logs;
|
||||
# Check the 'master_log.err-old' file is created
|
||||
# after executed 'flush error logs, relay logs' statement.
|
||||
# Make sure binary logs was not be flushed
|
||||
# after execute 'flush error logs, relay logs' statement.
|
||||
# Check the 'slave-relay-bin.000007' file is created after
|
||||
|
@ -55,12 +47,8 @@ flush error logs, relay logs;
|
|||
# Make sure the 'slave-relay-bin.000008' and 'slave-relay-bin.000009'
|
||||
# files do not exist before execute 'flush error logs, relay logs'
|
||||
# statement.
|
||||
# Make sure the 'master_log.err-old' file does not exist
|
||||
# before execute 'flush logs' statement.
|
||||
# Test if 'flush logs' statement works fine and flush all the logs.
|
||||
flush logs;
|
||||
# Check the 'master_log.err-old' file is created
|
||||
# after executed 'flush logs' statement.
|
||||
# Check 'master-bin.000003' is created
|
||||
# after execute 'flush logs' statement.
|
||||
# Check the 'slave-relay-bin.000008' and 'slave-relay-bin.000009'
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
##############################################################################
|
||||
|
||||
rpl_failed_optimize : WL#4284: Can't optimize table used by a pending transaction (there is metadata lock on the table).
|
||||
rpl_plugin_load : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
|
||||
rpl_read_only : WL#4284: Setting Read only won't succeed until all metadata locks are released.
|
||||
rpl_row_create_table : Bug#51574 2010-02-27 andrei failed different way than earlier with bug#45576
|
||||
rpl_spec_variables : BUG#47661 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux
|
||||
|
|
|
@ -10,3 +10,4 @@ drop table t1, t2;
|
|||
sync_slave_with_master;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
|
|
|
@ -9,17 +9,10 @@
|
|||
connection master;
|
||||
|
||||
# Test 'flush error logs' statement.
|
||||
--echo # Make sure the 'master_log.err-old' file does not
|
||||
--echo # exist before execute 'flush error logs' statement.
|
||||
--error 1
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
|
||||
--echo # Test if support 'flush error logs' statement.
|
||||
flush error logs;
|
||||
|
||||
--echo # Check the 'master_log.err-old' file is created
|
||||
--echo # after executed 'flush error logs' statement.
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
|
||||
|
||||
--echo # Make sure binary logs was not be flushed
|
||||
|
@ -109,19 +102,10 @@ sync_slave_with_master;
|
|||
file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000007;
|
||||
|
||||
connection master;
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
|
||||
--echo # Make sure the 'master_log.err-old' file does not exist
|
||||
--echo # before execute 'flush error logs, relay logs' statement.
|
||||
--error 1
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
|
||||
--echo # Test if support to combine all kinds of logs into one statement.
|
||||
flush error logs, relay logs;
|
||||
|
||||
--echo # Check the 'master_log.err-old' file is created
|
||||
--echo # after executed 'flush error logs, relay logs' statement.
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
|
||||
|
||||
--echo # Make sure binary logs was not be flushed
|
||||
|
@ -145,19 +129,10 @@ file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000008;
|
|||
file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000009;
|
||||
|
||||
connection master;
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
|
||||
--echo # Make sure the 'master_log.err-old' file does not exist
|
||||
--echo # before execute 'flush logs' statement.
|
||||
--error 1
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
|
||||
--echo # Test if 'flush logs' statement works fine and flush all the logs.
|
||||
flush logs;
|
||||
|
||||
--echo # Check the 'master_log.err-old' file is created
|
||||
--echo # after executed 'flush logs' statement.
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
|
||||
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
|
||||
|
||||
--echo # Check 'master-bin.000003' is created
|
||||
|
|
|
@ -540,4 +540,17 @@ DELETE FROM t1 WHERE a = 10 OR b = 20 ORDER BY c LIMIT 1;
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #53034: Multiple-table DELETE statements not accepting
|
||||
--echo # "Access compatibility" syntax
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (id INT);
|
||||
CREATE TABLE t2 LIKE t1;
|
||||
CREATE TABLE t3 LIKE t1;
|
||||
|
||||
DELETE FROM t1.*, test.t2.*, a.* USING t1, t2, t3 AS a;
|
||||
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
|
@ -14,9 +14,6 @@ lowercase_table3 : Bug#54845 2010-06-30 alik main.lowercase_table3 on Ma
|
|||
mysqlhotcopy_myisam : Bug#54129 2010-08-31 alik mysqlhotcopy* fails
|
||||
mysqlhotcopy_archive : Bug#54129 2010-08-31 alik mysqlhotcopy* fails
|
||||
partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings
|
||||
plugin : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
|
||||
plugin_load : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
|
||||
plugin_not_embedded : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
|
||||
query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically
|
||||
sp_sync : Bug#48157 2010-02-06 5.5-m3 demands a differnt solution
|
||||
ctype_utf8mb4_ndb : Bug#55799, Bug#51907, disabled by Konstantin 2010-08-06
|
||||
|
|
|
@ -708,6 +708,7 @@ SELECT 1 FROM
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
--echo #
|
||||
--echo # Bug #52397: another crash with explain extended and group_concat
|
||||
|
@ -722,6 +723,26 @@ DROP TABLE t1;
|
|||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Bug #54476: crash when group_concat and 'with rollup' in prepared statements
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1), (2);
|
||||
|
||||
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1.a ORDER BY t1.a) FROM t1 JOIN t1 t2 GROUP BY t1.a WITH ROLLUP";
|
||||
EXECUTE stmt;
|
||||
EXECUTE stmt;
|
||||
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Bug#36785: Wrong error message when group_concat() exceeds max length
|
||||
#
|
||||
|
|
|
@ -1082,6 +1082,20 @@ select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
|
|||
from t1 a, t1 b;
|
||||
select *, f1 = f2 from t1;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #54465: assert: field_types == 0 || field_types[field_pos] ==
|
||||
--echo # MYSQL_TYPE_LONGLONG
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (1), (2);
|
||||
|
||||
SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1
|
||||
ORDER BY t1.a;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
|
|
@ -467,6 +467,19 @@ select NAME_CONST('_id',1234) as id;
|
|||
|
||||
select connection_id() > 0;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #54461: crash with longblob and union or update with subquery
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b LONGBLOB);
|
||||
INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2');
|
||||
|
||||
SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
|
||||
SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Bug #52165: Assertion failed: file .\dtoa.c, line 465
|
||||
--echo #
|
||||
|
@ -478,4 +491,5 @@ SELECT COALESCE(a) = COALESCE(b) FROM t1;
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of tests
|
||||
|
|
|
@ -821,4 +821,15 @@ select date_sub("0069-01-01 00:00:01",INTERVAL 2 SECOND);
|
|||
select date_sub("0169-01-01 00:00:01",INTERVAL 2 SECOND);
|
||||
|
||||
|
||||
#
|
||||
# Bug #55565: debug assertion when ordering by expressions with user
|
||||
# variable assignments
|
||||
#
|
||||
|
||||
CREATE TABLE t1(a DOUBLE NOT NULL);
|
||||
INSERT INTO t1 VALUES (0),(9.216e-096);
|
||||
--echo # should not crash
|
||||
SELECT 1 FROM t1 ORDER BY @x:=makedate(a,a);
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
1
mysql-test/t/partition_not_blackhole-master.opt
Normal file
1
mysql-test/t/partition_not_blackhole-master.opt
Normal file
|
@ -0,0 +1 @@
|
|||
--loose-skip-blackhole
|
26
mysql-test/t/partition_not_blackhole.test
Normal file
26
mysql-test/t/partition_not_blackhole.test
Normal file
|
@ -0,0 +1,26 @@
|
|||
--source include/have_partition.inc
|
||||
--source include/not_blackhole.inc
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
let $MYSQLD_DATADIR= `SELECT @@datadir`;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#46086: crash when dropping a partitioned table and
|
||||
--echo # the original engine is disabled
|
||||
--echo # Copy a .frm and .par file which was created with:
|
||||
--echo # create table `t1` (`id` int primary key) engine=blackhole
|
||||
--echo # partition by key () partitions 1;
|
||||
--copy_file std_data/parts/t1_blackhole.frm $MYSQLD_DATADIR/test/t1.frm
|
||||
--copy_file std_data/parts/t1_blackhole.par $MYSQLD_DATADIR/test/t1.par
|
||||
SHOW TABLES;
|
||||
--replace_result $MYSQLD_DATADIR ./
|
||||
--error ER_NOT_FORM_FILE
|
||||
SHOW CREATE TABLE t1;
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
DROP TABLE t1;
|
||||
--list_files $MYSQLD_DATADIR/test t1*
|
||||
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
||||
--remove_file $MYSQLD_DATADIR/test/t1.par
|
|
@ -1313,4 +1313,16 @@ SELECT * FROM t1 FORCE INDEX (PRIMARY)
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #54802: 'NOT BETWEEN' evaluation is incorrect
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
|
||||
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||
|
||||
EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
|
@ -163,7 +163,6 @@ int handle_options(int *argc, char ***argv,
|
|||
int error, i;
|
||||
my_bool is_cmdline_arg= 1;
|
||||
|
||||
LINT_INIT(opt_found);
|
||||
/* handle_options() assumes arg0 (program name) always exists */
|
||||
DBUG_ASSERT(argc && *argc >= 1);
|
||||
DBUG_ASSERT(argv && *argv);
|
||||
|
@ -188,6 +187,7 @@ int handle_options(int *argc, char ***argv,
|
|||
{
|
||||
char **first= pos;
|
||||
char *cur_arg= *pos;
|
||||
opt_found= 0;
|
||||
if (!is_cmdline_arg && (cur_arg == args_separator))
|
||||
{
|
||||
is_cmdline_arg= 1;
|
||||
|
|
|
@ -477,7 +477,7 @@ static my_bool win32_init_tcp_ip()
|
|||
{
|
||||
if (win32_have_tcpip())
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD( 2, 0 );
|
||||
WORD wVersionRequested = MAKEWORD( 2, 2 );
|
||||
WSADATA wsaData;
|
||||
/* Be a good citizen: maybe another lib has already initialised
|
||||
sockets, so dont clobber them unless necessary */
|
||||
|
|
|
@ -91,6 +91,16 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
|
|||
LIST *thr_lock_thread_list; /* List of threads in use */
|
||||
ulong max_write_lock_count= ~(ulong) 0L;
|
||||
|
||||
static void (*before_lock_wait)(void)= 0;
|
||||
static void (*after_lock_wait)(void)= 0;
|
||||
|
||||
void thr_set_lock_wait_callback(void (*before_wait)(void),
|
||||
void (*after_wait)(void))
|
||||
{
|
||||
before_lock_wait= before_wait;
|
||||
after_lock_wait= after_wait;
|
||||
}
|
||||
|
||||
static inline mysql_cond_t *get_cond(void)
|
||||
{
|
||||
return &my_thread_var->suspend;
|
||||
|
@ -431,6 +441,19 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
|
|||
old_proc_info= proc_info_hook(NULL, "Waiting for table level lock",
|
||||
__func__, __FILE__, __LINE__);
|
||||
|
||||
/*
|
||||
Since before_lock_wait potentially can create more threads to
|
||||
scheduler work for, we don't want to call the before_lock_wait
|
||||
callback unless it will really start to wait.
|
||||
|
||||
For similar reasons, we do not want to call before_lock_wait and
|
||||
after_lock_wait for each lap around the loop, so we restrict
|
||||
ourselves to call it before_lock_wait once before starting to wait
|
||||
and once after the thread has exited the wait loop.
|
||||
*/
|
||||
if ((!thread_var->abort || in_wait_list) && before_lock_wait)
|
||||
(*before_lock_wait)();
|
||||
|
||||
set_timespec(wait_timeout, lock_wait_timeout);
|
||||
while (!thread_var->abort || in_wait_list)
|
||||
{
|
||||
|
@ -462,6 +485,14 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
|
|||
/* purecov: end */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We call the after_lock_wait callback once the wait loop has
|
||||
finished.
|
||||
*/
|
||||
if (after_lock_wait)
|
||||
(*after_lock_wait)();
|
||||
|
||||
DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d",
|
||||
thread_var->abort, in_wait_list));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -35,6 +35,8 @@ static void init_myfunc_errs(void);
|
|||
C_MODE_START
|
||||
static const char **get_server_errmsgs()
|
||||
{
|
||||
if (!current_thd)
|
||||
return DEFAULT_ERRMSGS;
|
||||
return CURRENT_THD_ERRMSGS;
|
||||
}
|
||||
C_MODE_END
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
117
sql/log.cc
117
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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,8 +1484,9 @@ 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();
|
||||
(void) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); // finish server errs
|
||||
DBUG_PRINT("quit", ("Error messages freed"));
|
||||
/* Tell main we are ready */
|
||||
logger.cleanup_end();
|
||||
|
@ -1752,7 +1758,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 +2006,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 +2402,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 +2410,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 +2657,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 +3744,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 +4361,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 +4448,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 +5019,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 +7335,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=
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
169
sql/scheduler.cc
169
sql/scheduler.cc
|
@ -25,30 +25,8 @@
|
|||
#include "unireg.h" // REQUIRED: for other includes
|
||||
#include "scheduler.h"
|
||||
#include "sql_connect.h" // init_new_connection_handler_thread
|
||||
|
||||
/*
|
||||
'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)
|
||||
{}
|
||||
|
||||
#include "scheduler.h"
|
||||
#include "sql_callback.h"
|
||||
|
||||
/*
|
||||
End connection, in case when we are using 'no-threads'
|
||||
|
@ -61,19 +39,89 @@ static bool no_threads_end(THD *thd, bool put_in_cache)
|
|||
return 1; // Abort handle_one_connection
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize scheduler for --thread-handling=one-thread-per-connection
|
||||
*/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
void one_thread_per_connection_scheduler()
|
||||
{
|
||||
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)
|
||||
{
|
||||
func->max_threads= max_connections;
|
||||
func->add_connection= create_thread_to_handle_connection;
|
||||
func->end_thread= one_thread_per_connection_end;
|
||||
#ifndef DBUG_OFF
|
||||
dbug_explain[0]= '\0';
|
||||
set_explain= FALSE;
|
||||
#endif
|
||||
}
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
#endif /* SCHEDULER_INCLUDED */
|
||||
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
|
||||
|
||||
thd_scheduler();
|
||||
~thd_scheduler();
|
||||
};
|
||||
|
||||
extern scheduler_functions *thread_scheduler;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -108,7 +108,7 @@ void sys_var_end()
|
|||
my_hash_free(&system_variable_hash);
|
||||
|
||||
for (sys_var *var=all_sys_vars.first; var; var= var->next)
|
||||
var->~sys_var();
|
||||
var->cleanup();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
|
|
@ -92,10 +92,9 @@ public:
|
|||
on_check_function on_check_func, on_update_function on_update_func,
|
||||
uint deprecated_version, const char *substitute, int parse_flag);
|
||||
/**
|
||||
The instance should only be destroyed on shutdown, as it doesn't unlink
|
||||
itself from the chain.
|
||||
All the cleanup procedures should be performed here
|
||||
*/
|
||||
virtual ~sys_var() {}
|
||||
virtual void cleanup() {}
|
||||
/**
|
||||
downcast for sys_var_pluginvar. Returns this if it's an instance
|
||||
of sys_var_pluginvar, and 0 otherwise.
|
||||
|
|
43
sql/sql_callback.h
Normal file
43
sql/sql_callback.h
Normal file
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -385,7 +385,7 @@ public:
|
|||
DBUG_ASSERT(scope() == GLOBAL);
|
||||
DBUG_ASSERT(size == sizeof(char *));
|
||||
}
|
||||
~Sys_var_charptr()
|
||||
void cleanup()
|
||||
{
|
||||
if (flags & ALLOCATED)
|
||||
my_free(global_var(char*));
|
||||
|
|
|
@ -204,7 +204,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 */
|
||||
|
|
|
@ -43,6 +43,8 @@ Created 11/11/1995 Heikki Tuuri
|
|||
#include "log0log.h"
|
||||
#include "os0file.h"
|
||||
#include "trx0sys.h"
|
||||
#include "mysql/plugin.h"
|
||||
#include "mysql/service_thd_wait.h"
|
||||
|
||||
/**********************************************************************
|
||||
These statistics are generated for heuristics used in estimating the
|
||||
|
@ -1744,10 +1746,14 @@ buf_flush_wait_batch_end(
|
|||
|
||||
buf_pool = buf_pool_from_array(i);
|
||||
|
||||
thd_wait_begin(NULL, THD_WAIT_DISKIO);
|
||||
os_event_wait(buf_pool->no_flush[type]);
|
||||
thd_wait_end(NULL);
|
||||
}
|
||||
} else {
|
||||
thd_wait_begin(NULL, THD_WAIT_DISKIO);
|
||||
os_event_wait(buf_pool->no_flush[type]);
|
||||
thd_wait_end(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ Created 11/5/1995 Heikki Tuuri
|
|||
#include "os0file.h"
|
||||
#include "srv0start.h"
|
||||
#include "srv0srv.h"
|
||||
#include "mysql/plugin.h"
|
||||
#include "mysql/service_thd_wait.h"
|
||||
|
||||
/** The linear read-ahead area size */
|
||||
#define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
|
||||
|
@ -135,6 +137,7 @@ buf_read_page_low(
|
|||
|
||||
ut_ad(buf_page_in_file(bpage));
|
||||
|
||||
thd_wait_begin(NULL, THD_WAIT_DISKIO);
|
||||
if (zip_size) {
|
||||
*err = fil_io(OS_FILE_READ | wake_later,
|
||||
sync, space, zip_size, offset, 0, zip_size,
|
||||
|
@ -146,6 +149,7 @@ buf_read_page_low(
|
|||
sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
|
||||
((buf_block_t*) bpage)->frame, bpage);
|
||||
}
|
||||
thd_wait_end(NULL);
|
||||
ut_a(*err == DB_SUCCESS);
|
||||
|
||||
if (sync) {
|
||||
|
|
|
@ -84,6 +84,8 @@ Created 10/8/1995 Heikki Tuuri
|
|||
#include "ha_prototypes.h"
|
||||
#include "trx0i_s.h"
|
||||
#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
|
||||
#include "mysql/plugin.h"
|
||||
#include "mysql/service_thd_wait.h"
|
||||
|
||||
/* This is set to TRUE if the MySQL user has set it in MySQL; currently
|
||||
affects only FOREIGN KEY definition parsing */
|
||||
|
@ -1232,7 +1234,9 @@ retry:
|
|||
|
||||
trx->op_info = "waiting in InnoDB queue";
|
||||
|
||||
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
|
||||
os_event_wait(slot->event);
|
||||
thd_wait_end(trx->mysql_thd);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
|
@ -1597,7 +1601,9 @@ srv_suspend_mysql_thread(
|
|||
|
||||
/* Suspend this thread and wait for the event. */
|
||||
|
||||
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
|
||||
os_event_wait(event);
|
||||
thd_wait_end(trx->mysql_thd);
|
||||
|
||||
/* After resuming, reacquire the data dictionary latch if
|
||||
necessary. */
|
||||
|
|
10
vio/vio.c
10
vio/vio.c
|
@ -44,6 +44,11 @@ static my_bool no_poll_read(Vio *vio __attribute__((unused)),
|
|||
|
||||
#endif
|
||||
|
||||
static my_bool has_no_data(Vio *vio __attribute__((unused)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to fill most of the Vio* with defaults.
|
||||
*/
|
||||
|
@ -83,6 +88,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
|
||||
vio->poll_read =no_poll_read;
|
||||
vio->is_connected =vio_is_connected_pipe;
|
||||
vio->has_data =has_no_data;
|
||||
|
||||
vio->timeout=vio_win32_timeout;
|
||||
/* Set default timeout */
|
||||
|
@ -110,6 +116,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
|
||||
vio->poll_read =no_poll_read;
|
||||
vio->is_connected =vio_is_connected_shared_memory;
|
||||
vio->has_data =has_no_data;
|
||||
|
||||
/* Currently, shared memory is on Windows only, hence the below is ok*/
|
||||
vio->timeout= vio_win32_timeout;
|
||||
|
@ -137,6 +144,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->timeout =vio_timeout;
|
||||
vio->poll_read =vio_poll_read;
|
||||
vio->is_connected =vio_is_connected;
|
||||
vio->has_data =vio_ssl_has_data;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
@ -155,6 +163,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->timeout =vio_timeout;
|
||||
vio->poll_read =vio_poll_read;
|
||||
vio->is_connected =vio_is_connected;
|
||||
vio->has_data= (flags & VIO_BUFFERED_READ) ?
|
||||
vio_buff_has_data : has_no_data;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ int vio_close_shared_memory(Vio * vio);
|
|||
#endif
|
||||
|
||||
void vio_timeout(Vio *vio,uint which, uint timeout);
|
||||
my_bool vio_buff_has_data(Vio *vio);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include "my_net.h" /* needed because of struct in_addr */
|
||||
|
@ -62,5 +63,7 @@ void vio_ssl_delete(Vio *vio);
|
|||
|
||||
int vio_ssl_blocking(Vio *vio, my_bool set_blocking_mode, my_bool *old_mode);
|
||||
|
||||
my_bool vio_ssl_has_data(Vio *vio);
|
||||
|
||||
#endif /* HAVE_OPENSSL */
|
||||
#endif /* VIO_PRIV_INCLUDED */
|
||||
|
|
|
@ -98,6 +98,10 @@ size_t vio_read_buff(Vio *vio, uchar* buf, size_t size)
|
|||
#undef VIO_UNBUFFERED_READ_MIN_SIZE
|
||||
}
|
||||
|
||||
my_bool vio_buff_has_data(Vio *vio)
|
||||
{
|
||||
return (vio->read_pos != vio->read_end);
|
||||
}
|
||||
|
||||
size_t vio_write(Vio * vio, const uchar* buf, size_t size)
|
||||
{
|
||||
|
|
|
@ -244,6 +244,9 @@ int vio_ssl_blocking(Vio *vio __attribute__((unused)),
|
|||
return (set_blocking_mode ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
my_bool vio_ssl_has_data(Vio *vio)
|
||||
{
|
||||
return SSL_pending(vio->ssl_arg) > 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
|
Loading…
Reference in a new issue