summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorGuilhem Bichot <guilhem.bichot@oracle.com>2011-05-21 10:59:32 +0200
committerGuilhem Bichot <guilhem.bichot@oracle.com>2011-05-21 10:59:32 +0200
commit27fa7876c8ad9a574bab5ab489a6d369a3d78947 (patch)
tree5ec3599cb2beed91477c85d0593eda12939c1c6e /sql
parent12f651ac9ddfb21187c69ae7a50c72440f7025c8 (diff)
parent34d731ef781d379fde668409ce264139d738aa4d (diff)
downloadmariadb-git-27fa7876c8ad9a574bab5ab489a6d369a3d78947.tar.gz
merge from latest 5.5
Diffstat (limited to 'sql')
-rw-r--r--sql/debug_sync.cc32
-rw-r--r--sql/debug_sync.h2
-rw-r--r--sql/item_func.cc6
-rw-r--r--sql/item_timefunc.cc9
-rw-r--r--sql/log.cc14
-rw-r--r--sql/log.h6
-rw-r--r--sql/mdl.cc6
-rw-r--r--sql/mysqld.cc49
-rw-r--r--sql/mysqld.h8
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/scheduler.cc27
-rw-r--r--sql/scheduler.h15
-rw-r--r--sql/sp_head.cc14
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/sql_class.cc271
-rw-r--r--sql/sql_class.h19
-rw-r--r--sql/sql_connect.cc39
-rw-r--r--sql/sql_connect.h2
-rw-r--r--sql/sql_cursor.h2
-rw-r--r--sql/sql_prepare.cc18
-rw-r--r--sql/sql_show.cc346
-rw-r--r--sql/table.cc3
22 files changed, 646 insertions, 248 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 4f353597d6d..7f69ae54037 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -1745,11 +1745,20 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
We don't use enter_cond()/exit_cond(). They do not save old
mutex and cond. This would prohibit the use of DEBUG_SYNC
between other places of enter_cond() and exit_cond().
+
+ We need to check for existence of thd->mysys_var to also make
+ it possible to use DEBUG_SYNC framework in scheduler when this
+ variable has been set to NULL.
*/
- old_mutex= thd->mysys_var->current_mutex;
- old_cond= thd->mysys_var->current_cond;
- thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
- thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
+ if (thd->mysys_var)
+ {
+ old_mutex= thd->mysys_var->current_mutex;
+ old_cond= thd->mysys_var->current_cond;
+ thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
+ thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
+ }
+ else
+ old_mutex= NULL;
set_timespec(abstime, action->timeout);
DBUG_EXECUTE("debug_sync_exec", {
@@ -1804,11 +1813,16 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
is locked. (See comment in THD::exit_cond().)
*/
mysql_mutex_unlock(&debug_sync_global.ds_mutex);
- mysql_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= old_mutex;
- thd->mysys_var->current_cond= old_cond;
- thd_proc_info(thd, old_proc_info);
- mysql_mutex_unlock(&thd->mysys_var->mutex);
+ if (old_mutex)
+ {
+ mysql_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= old_mutex;
+ thd->mysys_var->current_cond= old_cond;
+ thd_proc_info(thd, old_proc_info);
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
+ }
+ else
+ thd_proc_info(thd, old_proc_info);
}
else
{
diff --git a/sql/debug_sync.h b/sql/debug_sync.h
index 9ac7da39d4d..ba3739e8ad5 100644
--- a/sql/debug_sync.h
+++ b/sql/debug_sync.h
@@ -39,7 +39,7 @@ class THD;
} while (0)
/* Command line option --debug-sync-timeout. See mysqld.cc. */
-extern uint opt_debug_sync_timeout;
+extern MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout;
/* Default WAIT_FOR timeout if command line option is given without argument. */
#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300
diff --git a/sql/item_func.cc b/sql/item_func.cc
index def0590bef4..d0def6abccb 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -51,6 +51,8 @@
#include "sp.h"
#include "set_var.h"
#include "debug_sync.h"
+#include <mysql/plugin.h>
+#include <mysql/service_thd_wait.h>
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define sp_restore_security_context(A,B) while (0) {}
@@ -3889,6 +3891,7 @@ longlong Item_func_get_lock::val_int()
timed_cond.set_timeout(timeout * ULL(1000000000));
error= 0;
+ thd_wait_begin(thd, THD_WAIT_USER_LOCK);
while (ull->locked && !thd->killed)
{
DBUG_PRINT("info", ("waiting on lock"));
@@ -3900,6 +3903,7 @@ longlong Item_func_get_lock::val_int()
}
error= 0;
}
+ thd_wait_end(thd);
if (ull->locked)
{
@@ -4117,6 +4121,7 @@ longlong Item_func_sleep::val_int()
thd->mysys_var->current_cond= &cond;
error= 0;
+ thd_wait_begin(thd, THD_WAIT_SLEEP);
while (!thd->killed)
{
error= timed_cond.wait(&cond, &LOCK_user_locks);
@@ -4124,6 +4129,7 @@ longlong Item_func_sleep::val_int()
break;
error= 0;
}
+ thd_wait_end(thd);
thd_proc_info(thd, 0);
mysql_mutex_unlock(&LOCK_user_locks);
mysql_mutex_lock(&thd->mysys_var->mutex);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 0952a5448e4..b31a388bea4 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1591,6 +1591,11 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
return 1;
bzero(ltime, sizeof(MYSQL_TIME));
get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
+
+ if ((null_value= (fuzzy_date & TIME_NO_ZERO_DATE) &&
+ (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
+ return TRUE;
+
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return 0;
}
@@ -2779,7 +2784,7 @@ String *Item_func_makedate::val_str(String *str)
long days;
if (args[0]->null_value || args[1]->null_value ||
- year < 0 || daynr <= 0)
+ year < 0 || year > 9999 || daynr <= 0)
goto err;
if (year < 100)
@@ -2822,7 +2827,7 @@ longlong Item_func_makedate::val_int()
long days;
if (args[0]->null_value || args[1]->null_value ||
- year < 0 || daynr <= 0)
+ year < 0 || year > 9999 || daynr <= 0)
goto err;
if (year < 100)
diff --git a/sql/log.cc b/sql/log.cc
index 8f5db98a345..ce6b0f0a5a2 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5993,7 +5993,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
{
pg->next=pg+1;
pg->waiters=0;
- pg->state=POOL;
+ pg->state=PS_POOL;
mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_PAGE_cond, &pg->cond, 0);
pg->start=(my_xid *)(data + i*tc_log_page_size);
@@ -6167,7 +6167,7 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
*p->ptr++= xid;
p->free--;
- p->state= DIRTY;
+ p->state= PS_DIRTY;
/* to sync or not to sync - this is the question */
mysql_mutex_unlock(&LOCK_active);
@@ -6179,13 +6179,13 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
p->waiters++;
/*
note - it must be while (), not do ... while () here
- as p->state may be not DIRTY when we come here
+ as p->state may be not PS_DIRTY when we come here
*/
- while (p->state == DIRTY && syncing)
+ while (p->state == PS_DIRTY && syncing)
mysql_cond_wait(&p->cond, &LOCK_sync);
p->waiters--;
- err= p->state == ERROR;
- if (p->state != DIRTY) // page was synced
+ err= p->state == PS_ERROR;
+ if (p->state != PS_DIRTY) // page was synced
{
if (p->waiters == 0)
mysql_cond_signal(&COND_pool); // in case somebody's waiting
@@ -6223,7 +6223,7 @@ int TC_LOG_MMAP::sync()
pool_last->next=syncing;
pool_last=syncing;
syncing->next=0;
- syncing->state= err ? ERROR : POOL;
+ syncing->state= err ? PS_ERROR : PS_POOL;
mysql_cond_broadcast(&syncing->cond); // signal "sync done"
mysql_cond_signal(&COND_pool); // in case somebody's waiting
mysql_mutex_unlock(&LOCK_pool);
diff --git a/sql/log.h b/sql/log.h
index f6d60a2fe3c..0f0f81dd402 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -63,9 +63,9 @@ class TC_LOG_MMAP: public TC_LOG
{
public: // only to keep Sun Forte on sol9x86 happy
typedef enum {
- POOL, // page is in pool
- ERROR, // last sync failed
- DIRTY // new xids added since last sync
+ PS_POOL, // page is in pool
+ PS_ERROR, // last sync failed
+ PS_DIRTY // new xids added since last sync
} PAGE_STATE;
private:
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 3aed54ce12d..21410db2d22 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -18,6 +18,8 @@
#include "debug_sync.h"
#include <hash.h>
#include <mysqld_error.h>
+#include <mysql/plugin.h>
+#include <mysql/service_thd_wait.h>
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_MDL_map_mutex;
@@ -973,10 +975,14 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status,
wait_state_name);
+ thd_wait_begin(thd, THD_WAIT_META_DATA_LOCK);
while (!m_wait_status && !thd_killed(thd) &&
wait_result != ETIMEDOUT && wait_result != ETIME)
+ {
wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
abs_timeout);
+ }
+ thd_wait_end(thd);
if (m_wait_status == EMPTY)
{
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 52df837f193..d67a04bcc23 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -422,7 +422,7 @@ my_bool opt_super_large_pages= 0;
my_bool opt_myisam_use_mmap= 0;
uint opt_large_page_size= 0;
#if defined(ENABLED_DEBUG_SYNC)
-uint opt_debug_sync_timeout= 0;
+MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout= 0;
#endif /* defined(ENABLED_DEBUG_SYNC) */
my_bool opt_old_style_user_limits= 0, trust_function_creators= 0;
/*
@@ -2009,6 +2009,36 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
/*
+ Decrease number of connections
+
+ SYNOPSIS
+ dec_connection_count()
+*/
+
+void dec_connection_count()
+{
+ mysql_mutex_lock(&LOCK_connection_count);
+ --connection_count;
+ mysql_mutex_unlock(&LOCK_connection_count);
+}
+
+
+/*
+ Delete the THD object and decrease number of threads
+
+ SYNOPSIS
+ delete_thd()
+ thd Thread handler
+*/
+
+void delete_thd(THD *thd)
+{
+ thread_count--;
+ delete thd;
+}
+
+
+/*
Unlink thd from global list of available connections and free thd
SYNOPSIS
@@ -2023,15 +2053,10 @@ void unlink_thd(THD *thd)
{
DBUG_ENTER("unlink_thd");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
- thd->cleanup();
-
- mysql_mutex_lock(&LOCK_connection_count);
- --connection_count;
- mysql_mutex_unlock(&LOCK_connection_count);
+ dec_connection_count();
mysql_mutex_lock(&LOCK_thread_count);
- thread_count--;
- delete thd;
+ delete_thd(thd);
DBUG_VOID_RETURN;
}
@@ -4923,6 +4948,14 @@ static bool read_init_file(char *file_name)
}
+/**
+ Increment number of created threads
+*/
+void inc_thread_created(void)
+{
+ thread_created++;
+}
+
#ifndef EMBEDDED_LIBRARY
/*
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 303ee5bec0f..d2366224b3f 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -216,6 +216,10 @@ extern char err_shared_dir[];
extern TYPELIB thread_handling_typelib;
extern my_decimal decimal_zero;
+/*
+ THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread,
+ using my_pthread_setspecific_ptr()/my_thread_getspecific_ptr().
+*/
extern pthread_key(MEM_ROOT**,THR_MALLOC);
#ifdef HAVE_PSI_INTERFACE
@@ -503,6 +507,10 @@ get_thread_running()
extern "C" THD *_current_thd_noinline();
#define _current_thd() _current_thd_noinline()
#else
+/*
+ THR_THD is a key which will be used to set/get THD* for a thread,
+ using my_pthread_setspecific_ptr()/my_thread_getspecific_ptr().
+*/
extern pthread_key(THD*, THR_THD);
inline THD *_current_thd(void)
{
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index f2653894ea7..9a5c7521752 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -26,6 +26,8 @@
#include "rpl_utility.h"
#include "transaction.h"
#include "sql_parse.h" // end_trans, ROLLBACK
+#include <mysql/plugin.h>
+#include <mysql/service_thd_wait.h>
static int count_relay_log_space(Relay_log_info* rli);
@@ -799,6 +801,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
We are going to mysql_cond_(timed)wait(); if the SQL thread stops it
will wake us up.
*/
+ thd_wait_begin(thd, THD_WAIT_BINLOG);
if (timeout > 0)
{
/*
@@ -816,6 +819,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
}
else
mysql_cond_wait(&data_cond, &data_lock);
+ thd_wait_end(thd);
DBUG_PRINT("info",("Got signal of master update or timed out"));
if (error == ETIMEDOUT || error == ETIME)
{
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index d61a452b99e..a3848e20be5 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -80,14 +80,26 @@ scheduler_functions *thread_scheduler= NULL;
*/
/**@{*/
-static void scheduler_wait_begin(void) {
+extern "C"
+{
+static void scheduler_wait_lock_begin(void) {
+ MYSQL_CALLBACK(thread_scheduler,
+ thd_wait_begin, (current_thd, THD_WAIT_TABLE_LOCK));
+}
+
+static void scheduler_wait_lock_end(void) {
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
+}
+
+static void scheduler_wait_sync_begin(void) {
MYSQL_CALLBACK(thread_scheduler,
- thd_wait_begin, (current_thd, THD_WAIT_ROW_TABLE_LOCK));
+ thd_wait_begin, (current_thd, THD_WAIT_TABLE_LOCK));
}
-static void scheduler_wait_end(void) {
+static void scheduler_wait_sync_end(void) {
MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
}
+};
/**@}*/
/**
@@ -98,7 +110,10 @@ static void scheduler_wait_end(void) {
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);
+ thr_set_lock_wait_callback(scheduler_wait_lock_begin,
+ scheduler_wait_lock_end);
+ thr_set_sync_wait_callback(scheduler_wait_sync_begin,
+ scheduler_wait_sync_end);
}
/*
@@ -137,10 +152,6 @@ void one_thread_scheduler()
thd_scheduler::thd_scheduler()
: m_psi(NULL), data(NULL)
{
-#ifndef DBUG_OFF
- dbug_explain[0]= '\0';
- set_explain= FALSE;
-#endif
}
diff --git a/sql/scheduler.h b/sql/scheduler.h
index b5a175434b6..7cf54dec004 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -72,11 +72,6 @@ enum scheduler_types
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
-};
-
/*
To be used for pool-of-threads (implemeneted differently on various OSs)
*/
@@ -97,15 +92,15 @@ public:
void *data; /* scheduler-specific data structure */
-# ifndef DBUG_OFF
- char dbug_explain[512];
- bool set_explain;
-# endif
-
thd_scheduler();
~thd_scheduler();
};
+void *thd_get_scheduler_data(THD *thd);
+void thd_set_scheduler_data(THD *thd, void *data);
+PSI_thread* thd_get_psi(THD *thd);
+void thd_set_psi(THD *thd, PSI_thread *psi);
+
extern scheduler_functions *thread_scheduler;
#endif
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index d6ae8a47c73..a4010a587cc 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -550,7 +550,7 @@ sp_head::operator delete(void *ptr, size_t size) throw()
sp_head::sp_head()
- :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
+ :Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
m_flags(0),
m_sp_cache_version(0),
unsafe_flags(0),
@@ -1208,7 +1208,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
Query_arena *old_arena;
/* per-instruction arena */
MEM_ROOT execute_mem_root;
- Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
+ Query_arena execute_arena(&execute_mem_root, STMT_INITIALIZED_FOR_SP),
backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
@@ -1489,7 +1489,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
thd->m_reprepare_observer= save_reprepare_observer;
thd->stmt_arena= old_arena;
- state= EXECUTED;
+ state= STMT_EXECUTED;
/*
Restore the caller's original warning information area:
@@ -1647,7 +1647,7 @@ sp_head::execute_trigger(THD *thd,
sp_rcontext *nctx = NULL;
bool err_status= FALSE;
MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
+ Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
Query_arena backup_arena;
DBUG_ENTER("sp_head::execute_trigger");
@@ -1788,7 +1788,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
String binlog_buf(buf, sizeof(buf), &my_charset_bin);
bool err_status= FALSE;
MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
+ Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
Query_arena backup_arena;
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
@@ -2545,7 +2545,7 @@ sp_head::restore_thd_mem_root(THD *thd)
DBUG_ENTER("sp_head::restore_thd_mem_root");
Item *flist= free_list; // The old list
set_query_arena(thd); // Get new free_list and mem_root
- state= INITIALIZED_FOR_SP;
+ state= STMT_INITIALIZED_FOR_SP;
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
@@ -3009,7 +3009,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
(thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE &&
thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE &&
thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED))
- thd->stmt_arena->state= Query_arena::EXECUTED;
+ thd->stmt_arena->state= Query_arena::STMT_EXECUTED;
/*
Merge here with the saved parent's values
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 5efd48fc7c6..4d5e2dd95ab 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -560,7 +560,7 @@ public:
/// Should give each a name or type code for debugging purposes?
sp_instr(uint ip, sp_pcontext *ctx)
- :Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx)
+ :Query_arena(0, STMT_INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx)
{}
virtual ~sp_instr()
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 1780d1b6a13..7c2ed133f70 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -217,6 +217,252 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
+/**
+ Get reference to scheduler data object
+
+ @param thd THD object
+
+ @retval Scheduler data object on THD
+*/
+void *thd_get_scheduler_data(THD *thd)
+{
+ return thd->scheduler.data;
+}
+
+/**
+ Set reference to Scheduler data object for THD object
+
+ @param thd THD object
+ @param psi Scheduler data object to set on THD
+*/
+void thd_set_scheduler_data(THD *thd, void *data)
+{
+ thd->scheduler.data= data;
+}
+
+/**
+ Get reference to Performance Schema object for THD object
+
+ @param thd THD object
+
+ @retval Performance schema object for thread on THD
+*/
+PSI_thread *thd_get_psi(THD *thd)
+{
+ return thd->scheduler.m_psi;
+}
+
+/**
+ Set reference to Performance Schema object for THD object
+
+ @param thd THD object
+ @param psi Performance schema object for thread
+*/
+void thd_set_psi(THD *thd, PSI_thread *psi)
+{
+ thd->scheduler.m_psi= psi;
+}
+
+/**
+ Set the state on connection to killed
+
+ @param thd THD object
+*/
+void thd_set_killed(THD *thd)
+{
+ thd->killed= THD::KILL_CONNECTION;
+}
+
+/**
+ Clear errors from the previous THD
+
+ @param thd THD object
+*/
+void thd_clear_errors(THD *thd)
+{
+ my_errno= 0;
+ thd->mysys_var->abort= 0;
+}
+
+/**
+ Set thread stack in THD object
+
+ @param thd Thread object
+ @param stack_start Start of stack to set in THD object
+*/
+void thd_set_thread_stack(THD *thd, char *stack_start)
+{
+ thd->thread_stack= stack_start;
+}
+
+/**
+ Lock connection data for the set of connections this connection
+ belongs to
+
+ @param thd THD object
+*/
+void thd_lock_thread_count(THD *)
+{
+ mysql_mutex_lock(&LOCK_thread_count);
+}
+
+/**
+ Lock connection data for the set of connections this connection
+ belongs to
+
+ @param thd THD object
+*/
+void thd_unlock_thread_count(THD *)
+{
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+}
+
+/**
+ Close the socket used by this connection
+
+ @param thd THD object
+*/
+void thd_close_connection(THD *thd)
+{
+ if (thd->net.vio)
+ vio_close(thd->net.vio);
+}
+
+/**
+ Get current THD object from thread local data
+
+ @retval The THD object for the thread, NULL if not connection thread
+*/
+THD *thd_get_current_thd()
+{
+ return current_thd;
+}
+
+/**
+ Set up various THD data for a new connection
+
+ thd_new_connection_setup
+
+ @param thd THD object
+ @param stack_start Start of stack for connection
+*/
+void thd_new_connection_setup(THD *thd, char *stack_start)
+{
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ thd_set_psi(thd,
+ PSI_server->new_thread(key_thread_one_connection,
+ thd,
+ thd_get_thread_id((MYSQL_THD)thd)));
+#endif
+ thd->set_time();
+ thd->prior_thr_create_utime= thd->thr_create_utime= thd->start_utime=
+ my_micro_time();
+ threads.append(thd);
+ thd_unlock_thread_count(thd);
+ DBUG_PRINT("info", ("init new connection. thd: 0x%lx fd: %d",
+ (ulong)thd, thd->net.vio->sd));
+ thd_set_thread_stack(thd, stack_start);
+}
+
+/**
+ Lock data that needs protection in THD object
+
+ @param thd THD object
+*/
+void thd_lock_data(THD *thd)
+{
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+}
+
+/**
+ Unlock data that needs protection in THD object
+
+ @param thd THD object
+*/
+void thd_unlock_data(THD *thd)
+{
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+}
+
+/**
+ Support method to check if connection has already started transcaction
+
+ @param client_cntx Low level client context
+
+ @retval TRUE if connection already started transaction
+*/
+bool thd_is_transaction_active(THD *thd)
+{
+ return thd->transaction.is_active();
+}
+
+/**
+ Check if there is buffered data on the socket representing the connection
+
+ @param thd THD object
+*/
+int thd_connection_has_data(THD *thd)
+{
+ Vio *vio= thd->net.vio;
+ return vio->has_data(vio);
+}
+
+/**
+ Set reading/writing on socket, used by SHOW PROCESSLIST
+
+ @param thd THD object
+ @param val Value to set it to (0 or 1)
+*/
+void thd_set_net_read_write(THD *thd, uint val)
+{
+ thd->net.reading_or_writing= val;
+}
+
+/**
+ Set reference to mysys variable in THD object
+
+ @param thd THD object
+ @param mysys_var Reference to set
+*/
+void thd_set_mysys_var(THD *thd, st_my_thread_var *mysys_var)
+{
+ thd->set_mysys_var(mysys_var);
+}
+
+/**
+ Get socket file descriptor for this connection
+
+ @param thd THD object
+
+ @retval Socket of the connection
+*/
+my_socket thd_get_fd(THD *thd)
+{
+ return thd->net.vio->sd;
+}
+
+/**
+ Get thread attributes for connection threads
+
+ @retval Reference to thread attribute for connection threads
+*/
+pthread_attr_t *get_connection_attrib(void)
+{
+ return &connection_attrib;
+}
+
+/**
+ Get max number of connections
+
+ @retval Max number of connections for MySQL Server
+*/
+ulong get_max_connections(void)
+{
+ return max_connections;
+}
+
/*
The following functions form part of the C plugin API
*/
@@ -494,7 +740,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd,
THD::THD()
- :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
+ :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
rli_fake(0),
user_time(0), in_sub_stmt(0),
@@ -1355,6 +1601,25 @@ bool THD::store_globals()
return 0;
}
+/*
+ Remove the thread specific info (THD and mem_root pointer) stored during
+ store_global call for this thread.
+*/
+bool THD::restore_globals()
+{
+ /*
+ Assert that thread_stack is initialized: it's necessary to be able
+ to track stack overrun.
+ */
+ DBUG_ASSERT(thread_stack);
+
+ /* Undocking the thread specific data. */
+ my_pthread_setspecific_ptr(THR_THD, NULL);
+ my_pthread_setspecific_ptr(THR_MALLOC, NULL);
+
+ return 0;
+}
+
/*
Cleanup after query.
@@ -3298,7 +3563,7 @@ extern "C" void thd_pool_wait_end(MYSQL_THD thd);
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)
+extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
{
MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type));
}
@@ -3314,7 +3579,7 @@ 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)
+extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
{
/* do NOTHING for the embedded library */
return;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 56d85e7cb6d..a2c622b2326 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -624,14 +624,14 @@ public:
/*
The states relfects three diffrent life cycles for three
different types of statements:
- Prepared statement: INITIALIZED -> PREPARED -> EXECUTED.
- Stored procedure: INITIALIZED_FOR_SP -> EXECUTED.
- Other statements: CONVENTIONAL_EXECUTION never changes.
+ Prepared statement: STMT_INITIALIZED -> STMT_PREPARED -> STMT_EXECUTED.
+ Stored procedure: STMT_INITIALIZED_FOR_SP -> STMT_EXECUTED.
+ Other statements: STMT_CONVENTIONAL_EXECUTION never changes.
*/
enum enum_state
{
- INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2,
- CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1
+ STMT_INITIALIZED= 0, STMT_INITIALIZED_FOR_SP= 1, STMT_PREPARED= 2,
+ STMT_CONVENTIONAL_EXECUTION= 3, STMT_EXECUTED= 4, STMT_ERROR= -1
};
enum_state state;
@@ -654,13 +654,13 @@ public:
virtual Type type() const;
virtual ~Query_arena() {};
- inline bool is_stmt_prepare() const { return state == INITIALIZED; }
+ inline bool is_stmt_prepare() const { return state == STMT_INITIALIZED; }
inline bool is_stmt_prepare_or_first_sp_execute() const
- { return (int)state < (int)PREPARED; }
+ { return (int)state < (int)STMT_PREPARED; }
inline bool is_stmt_prepare_or_first_stmt_execute() const
- { return (int)state <= (int)PREPARED; }
+ { return (int)state <= (int)STMT_PREPARED; }
inline bool is_conventional() const
- { return state == CONVENTIONAL_EXECUTION; }
+ { return state == STMT_CONVENTIONAL_EXECUTION; }
inline void* alloc(size_t size) { return alloc_root(mem_root,size); }
inline void* calloc(size_t size)
@@ -2199,6 +2199,7 @@ public:
void cleanup(void);
void cleanup_after_query();
bool store_globals();
+ bool restore_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio)
{
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b4ae68b33d1..c3b978d7659 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -707,6 +707,32 @@ pthread_handler_t handle_one_connection(void *arg)
return 0;
}
+bool thd_prepare_connection(THD *thd)
+{
+ bool rc;
+ lex_start(thd);
+ rc= login_connection(thd);
+ MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
+ if (rc)
+ return rc;
+
+ MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0],
+ (char *) thd->security_ctx->host_or_ip);
+
+ prepare_new_connection_state(thd);
+ return FALSE;
+}
+
+bool thd_is_connection_alive(THD *thd)
+{
+ NET *net= &thd->net;
+ if (!net->error &&
+ net->vio != 0 &&
+ !(thd->killed == THD::KILL_CONNECTION))
+ return TRUE;
+ return FALSE;
+}
+
void do_handle_one_connection(THD *thd_arg)
{
THD *thd= thd_arg;
@@ -749,22 +775,13 @@ void do_handle_one_connection(THD *thd_arg)
for (;;)
{
- NET *net= &thd->net;
bool rc;
- lex_start(thd);
- rc= login_connection(thd);
- MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
+ rc= thd_prepare_connection(thd);
if (rc)
goto end_thread;
- MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0],
- (char *) thd->security_ctx->host_or_ip);
-
- prepare_new_connection_state(thd);
-
- while (!net->error && net->vio != 0 &&
- !(thd->killed == THD::KILL_CONNECTION))
+ while (thd_is_connection_alive(thd))
{
mysql_audit_release(thd);
if (do_command(thd))
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index ff5a20dfbc2..1b71d95323d 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -35,6 +35,8 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
void decrease_user_connections(USER_CONN *uc);
bool thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd);
+bool thd_prepare_connection(THD *thd);
+bool thd_is_connection_alive(THD *thd);
int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h
index ed7bfac821a..d19d14fa167 100644
--- a/sql/sql_cursor.h
+++ b/sql/sql_cursor.h
@@ -46,7 +46,7 @@ protected:
select_result *result;
public:
Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg)
- :Query_arena(mem_root_arg, INITIALIZED), result(result_arg)
+ :Query_arena(mem_root_arg, STMT_INITIALIZED), result(result_arg)
{}
virtual bool is_open() const= 0;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index dd9ec594f29..7f2ab1aeb8e 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2712,7 +2712,7 @@ void mysqld_stmt_reset(THD *thd, char *packet)
*/
reset_stmt_params(stmt);
- stmt->state= Query_arena::PREPARED;
+ stmt->state= Query_arena::STMT_PREPARED;
general_log_print(thd, thd->command, NullS);
@@ -2831,7 +2831,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
- stmt->state= Query_arena::ERROR;
+ stmt->state= Query_arena::STMT_ERROR;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysqld_stmt_send_long_data");
@@ -2855,7 +2855,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
#endif
if (thd->stmt_da->is_error())
{
- stmt->state= Query_arena::ERROR;
+ stmt->state= Query_arena::STMT_ERROR;
stmt->last_errno= thd->stmt_da->sql_errno();
strncpy(stmt->last_error, thd->stmt_da->message(), MYSQL_ERRMSG_SIZE);
}
@@ -3010,7 +3010,7 @@ end:
Prepared_statement::Prepared_statement(THD *thd_arg)
:Statement(NULL, &main_mem_root,
- INITIALIZED, ++thd_arg->statement_id_counter),
+ STMT_INITIALIZED, ++thd_arg->statement_id_counter),
thd(thd_arg),
result(thd_arg),
param_array(0),
@@ -3283,7 +3283,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
{
setup_set_params();
lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE;
- state= Query_arena::PREPARED;
+ state= Query_arena::STMT_PREPARED;
flags&= ~ (uint) IS_IN_USE;
/*
@@ -3401,7 +3401,7 @@ Prepared_statement::execute_loop(String *expanded_query,
int reprepare_attempt= 0;
/* Check if we got an error when sending long data */
- if (state == Query_arena::ERROR)
+ if (state == Query_arena::STMT_ERROR)
{
my_message(last_errno, last_error, MYF(0));
return TRUE;
@@ -3464,7 +3464,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
Item_change_list save_change_list;
thd->change_list.move_elements_to(&save_change_list);
- state= CONVENTIONAL_EXECUTION;
+ state= STMT_CONVENTIONAL_EXECUTION;
if (!(lex= new (mem_root) st_lex_local))
return TRUE;
@@ -3799,8 +3799,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
thd->set_statement(&stmt_backup);
thd->stmt_arena= old_stmt_arena;
- if (state == Query_arena::PREPARED)
- state= Query_arena::EXECUTED;
+ if (state == Query_arena::STMT_PREPARED)
+ state= Query_arena::STMT_EXECUTED;
if (error == 0 && this->lex->sql_command == SQLCOM_CALL)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9e9de5e3524..61a2287419c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2407,12 +2407,11 @@ bool schema_table_store_record(THD *thd, TABLE *table)
}
-int make_table_list(THD *thd, SELECT_LEX *sel,
- LEX_STRING *db_name, LEX_STRING *table_name)
+static int make_table_list(THD *thd, SELECT_LEX *sel,
+ LEX_STRING *db_name, LEX_STRING *table_name)
{
Table_ident *table_ident;
table_ident= new Table_ident(thd, *db_name, *table_name, 1);
- sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
return 1;
return 0;
@@ -2982,91 +2981,190 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
/**
- @brief Fill I_S table for SHOW COLUMNS|INDEX commands
+ Fill I_S table with data obtained by performing full-blown table open.
+
+ @param thd Thread handler.
+ @param is_show_fields_or_keys Indicates whether it is a legacy SHOW
+ COLUMNS or SHOW KEYS statement.
+ @param table TABLE object for I_S table to be filled.
+ @param schema_table I_S table description structure.
+ @param orig_db_name Database name.
+ @param orig_table_name Table name.
+ @param open_tables_state_backup Open_tables_state object which is used
+ to save/restore original status of
+ variables related to open tables state.
+ @param can_deadlock Indicates that deadlocks are possible
+ due to metadata locks, so to avoid
+ them we should not wait in case if
+ conflicting lock is present.
+
+ @retval FALSE - Success.
+ @retval TRUE - Failure.
+*/
+static bool
+fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
+ TABLE *table, ST_SCHEMA_TABLE *schema_table,
+ LEX_STRING *orig_db_name,
+ LEX_STRING *orig_table_name,
+ Open_tables_backup *open_tables_state_backup,
+ bool can_deadlock)
+{
+ Query_arena i_s_arena(thd->mem_root,
+ Query_arena::STMT_CONVENTIONAL_EXECUTION),
+ backup_arena, *old_arena;
+ LEX *old_lex= thd->lex, temp_lex, *lex;
+ LEX_STRING db_name, table_name;
+ TABLE_LIST *table_list;
+ bool result= true;
+
+ DBUG_ENTER("fill_schema_table_by_open");
+ /*
+ When a view is opened its structures are allocated on a permanent
+ statement arena and linked into the LEX tree for the current statement
+ (this happens even in cases when view is handled through TEMPTABLE
+ algorithm).
- @param[in] thd thread handler
- @param[in] tables TABLE_LIST for I_S table
- @param[in] schema_table pointer to I_S structure
- @param[in] can_deadlock Indicates that deadlocks are possible
- due to metadata locks, so to avoid
- them we should not wait in case if
- conflicting lock is present.
- @param[in] open_tables_state_backup pointer to Open_tables_backup object
- which is used to save|restore original
- status of variables related to
- open tables state
+ To prevent this process from unnecessary hogging of memory in the permanent
+ arena of our I_S query and to avoid damaging its LEX we use temporary
+ arena and LEX for table/view opening.
- @return Operation status
- @retval 0 success
- @retval 1 error
-*/
+ Use temporary arena instead of statement permanent arena. Also make
+ it active arena and save original one for successive restoring.
+ */
+ old_arena= thd->stmt_arena;
+ thd->stmt_arena= &i_s_arena;
+ thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
-static int
-fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
- ST_SCHEMA_TABLE *schema_table,
- bool can_deadlock,
- Open_tables_backup *open_tables_state_backup)
-{
- LEX *lex= thd->lex;
- bool res;
- LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
- enum_sql_command save_sql_command= lex->sql_command;
- TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first;
- TABLE *table= tables->table;
- int error= 1;
- DBUG_ENTER("fill_schema_show");
+ /* Prepare temporary LEX. */
+ thd->lex= lex= &temp_lex;
+ lex_start(thd);
+
+ /* Disable constant subquery evaluation as we won't be locking tables. */
+ lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
+
+ /*
+ Some of process_table() functions rely on wildcard being passed from
+ old LEX (or at least being initialized).
+ */
+ lex->wild= old_lex->wild;
+
+ /*
+ Since make_table_list() might change database and table name passed
+ to it we create copies of orig_db_name and orig_table_name here.
+ These copies are used for make_table_list() while unaltered values
+ are passed to process_table() functions.
+ */
+ if (!thd->make_lex_string(&db_name, orig_db_name->str,
+ orig_db_name->length, FALSE) ||
+ !thd->make_lex_string(&table_name, orig_table_name->str,
+ orig_table_name->length, FALSE))
+ goto end;
- lex->all_selects_list= tables->schema_select_lex;
/*
- Restore thd->temporary_tables to be able to process
- temporary tables(only for 'show index' & 'show columns').
- This should be changed when processing of temporary tables for
- I_S tables will be done.
+ Create table list element for table to be open. Link it with the
+ temporary LEX. The latter is required to correctly open views and
+ produce table describing their structure.
*/
- thd->temporary_tables= open_tables_state_backup->temporary_tables;
+ if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
+ goto end;
+
+ table_list= lex->select_lex.table_list.first;
+
+ if (is_show_fields_or_keys)
+ {
+ /*
+ Restore thd->temporary_tables to be able to process
+ temporary tables (only for 'show index' & 'show columns').
+ This should be changed when processing of temporary tables for
+ I_S tables will be done.
+ */
+ thd->temporary_tables= open_tables_state_backup->temporary_tables;
+ }
+ else
+ {
+ /*
+ Apply optimization flags for table opening which are relevant for
+ this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
+ backward compatibility.
+ */
+ table_list->i_s_requested_object= schema_table->i_s_requested_object;
+ }
+
/*
Let us set fake sql_command so views won't try to merge
themselves into main statement. If we don't do this,
SELECT * from information_schema.xxxx will cause problems.
- SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
+ SQLCOM_SHOW_FIELDS is used because it satisfies
+ 'only_view_structure()'.
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
- res= open_normal_and_derived_tables(thd, show_table_list,
- (MYSQL_OPEN_IGNORE_FLUSH |
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
- (can_deadlock ?
- MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
- lex->sql_command= save_sql_command;
+ result= open_normal_and_derived_tables(thd, table_list,
+ (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+ (can_deadlock ?
+ MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+ /*
+ Restore old value of sql_command back as it is being looked at in
+ process_table() function.
+ */
+ lex->sql_command= old_lex->sql_command;
DEBUG_SYNC(thd, "after_open_table_ignore_flush");
/*
- get_all_tables() returns 1 on failure and 0 on success thus
- return only these and not the result code of ::process_table()
-
- We should use show_table_list->alias instead of
- show_table_list->table_name because table_name
- could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case(this part of code is used only for
- 'show columns' & 'show statistics' commands).
+ XXX: show_table_list has a flag i_is_requested,
+ and when it's set, open_normal_and_derived_tables()
+ can return an error without setting an error message
+ in THD, which is a hack. This is why we have to
+ check for res, then for thd->is_error() and only then
+ for thd->main_da.sql_errno().
+
+ Again we don't do this for SHOW COLUMNS/KEYS because
+ of backward compatibility.
*/
- table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
- strlen(show_table_list->alias), FALSE);
- if (!show_table_list->view)
- db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db,
- show_table_list->db_length, FALSE);
- else
- db_name= &show_table_list->view_db;
-
-
- error= test(schema_table->process_table(thd, show_table_list,
- table, res, db_name,
- table_name));
- thd->temporary_tables= 0;
- close_tables_for_reopen(thd, &show_table_list,
- open_tables_state_backup->mdl_system_tables_svp);
- DBUG_RETURN(error);
+ if (!is_show_fields_or_keys && result && thd->is_error() &&
+ thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
+ {
+ /*
+ Hide error for a non-existing table.
+ For example, this error can occur when we use a where condition
+ with a db name and table, but the table does not exist.
+ */
+ result= false;
+ thd->clear_error();
+ }
+ else
+ {
+ result= schema_table->process_table(thd, table_list,
+ table, result,
+ orig_db_name,
+ orig_table_name);
+ }
+
+
+end:
+ lex->unit.cleanup();
+
+ /* Restore original LEX value, statement's arena and THD arena values. */
+ lex_end(thd->lex);
+
+ if (i_s_arena.free_list)
+ i_s_arena.free_items();
+
+ /*
+ For safety reset list of open temporary tables before closing
+ all tables open within this Open_tables_state.
+ */
+ thd->temporary_tables= NULL;
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
+
+ thd->lex= old_lex;
+
+ thd->stmt_arena= old_arena;
+ thd->restore_active_arena(&i_s_arena, &backup_arena);
+
+ DBUG_RETURN(result);
}
@@ -3477,10 +3575,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- SELECT_LEX *old_all_select_lex= lex->all_selects_list;
SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
- SELECT_LEX sel;
LOOKUP_FIELD_VALUES lookup_field_vals;
LEX_STRING *db_name, *table_name;
bool with_i_schema;
@@ -3488,11 +3584,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
List<LEX_STRING> db_names;
List_iterator_fast<LEX_STRING> it(db_names);
COND *partial_cond= 0;
- uint derived_tables= lex->derived_tables;
int error= 1;
Open_tables_backup open_tables_state_backup;
- uint8 save_context_analysis_only= lex->context_analysis_only;
- Query_tables_list query_tables_list_backup;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
#endif
@@ -3511,15 +3604,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
can_deadlock= thd->mdl_context.has_locks();
- lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
- lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
- /*
- Restore Query_tables_list::sql_command value, which was reset
- above, as ST_SCHEMA_TABLE::process_table() functions often rely
- that this value reflects which SHOW statement is executed.
- */
- lex->sql_command= query_tables_list_backup.sql_command;
-
/*
We should not introduce deadlocks even if we already have some
tables open and locked, since we won't lock tables which we will
@@ -3539,9 +3623,19 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
if (lsel && lsel->table_list.first)
{
- error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
- can_deadlock,
- &open_tables_state_backup);
+ LEX_STRING db_name, table_name;
+
+ db_name.str= lsel->table_list.first->db;
+ db_name.length= lsel->table_list.first->db_length;
+
+ table_name.str= lsel->table_list.first->table_name;
+ table_name.length= lsel->table_list.first->table_name_length;
+
+ error= fill_schema_table_by_open(thd, TRUE,
+ table, schema_table,
+ &db_name, &table_name,
+ &open_tables_state_backup,
+ can_deadlock);
goto err;
}
@@ -3595,12 +3689,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
it.rewind(); /* To get access to new elements in basis list */
while ((db_name= it++))
{
- LEX_STRING orig_db_name;
-
- /* db_name can be changed in make_table_list() func */
- if (!thd->make_lex_string(&orig_db_name, db_name->str,
- db_name->length, FALSE))
- goto err;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(check_access(thd, SELECT_ACL, db_name->str,
&thd->col_access, NULL, 0, 1) ||
@@ -3678,66 +3766,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
continue;
}
- int res;
- LEX_STRING tmp_lex_string;
- /*
- Set the parent lex of 'sel' because it is needed by
- sel.init_query() which is called inside make_table_list.
- */
- sel.parent_lex= lex;
- if (make_table_list(thd, &sel, db_name, table_name))
- goto err;
- TABLE_LIST *show_table_list= sel.table_list.first;
- lex->all_selects_list= &sel;
- lex->derived_tables= 0;
- lex->sql_command= SQLCOM_SHOW_FIELDS;
- show_table_list->i_s_requested_object=
- schema_table->i_s_requested_object;
- DEBUG_SYNC(thd, "before_open_in_get_all_tables");
- res= open_normal_and_derived_tables(thd, show_table_list,
- (MYSQL_OPEN_IGNORE_FLUSH |
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
- (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
- lex->sql_command= query_tables_list_backup.sql_command;
- /*
- XXX: show_table_list has a flag i_is_requested,
- and when it's set, open_normal_and_derived_tables()
- can return an error without setting an error message
- in THD, which is a hack. This is why we have to
- check for res, then for thd->is_error() only then
- for thd->stmt_da->sql_errno().
- */
- if (res && thd->is_error() &&
- thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
- {
- /*
- Hide error for not existing table.
- This error can occur for example when we use
- where condition with db name and table name and this
- table does not exist.
- */
- res= 0;
- thd->clear_error();
- }
- else
- {
- /*
- We should use show_table_list->alias instead of
- show_table_list->table_name because table_name
- could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case.
- */
- thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
- strlen(show_table_list->alias), FALSE);
- res= schema_table->process_table(thd, show_table_list, table,
- res, &orig_db_name,
- &tmp_lex_string);
- close_tables_for_reopen(thd, &show_table_list,
- open_tables_state_backup.mdl_system_tables_svp);
- }
- DBUG_ASSERT(!lex->query_tables_own_last);
- if (res)
+ if (fill_schema_table_by_open(thd, FALSE,
+ table, schema_table,
+ db_name, table_name,
+ &open_tables_state_backup,
+ can_deadlock))
goto err;
}
}
@@ -3753,10 +3786,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
error= 0;
err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
- lex->restore_backup_query_tables_list(&query_tables_list_backup);
- lex->derived_tables= derived_tables;
- lex->all_selects_list= old_all_select_lex;
- lex->context_analysis_only= save_context_analysis_only;
+
DBUG_RETURN(error);
}
diff --git a/sql/table.cc b/sql/table.cc
index 1ac17d18d8d..351e80627eb 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1992,7 +1992,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
Query_arena backup_arena;
- Query_arena part_func_arena(&outparam->mem_root, Query_arena::INITIALIZED);
+ Query_arena part_func_arena(&outparam->mem_root,
+ Query_arena::STMT_INITIALIZED);
thd->set_n_backup_active_arena(&part_func_arena, &backup_arena);
thd->stmt_arena= &part_func_arena;
bool tmp;