mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 10:56:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1290 lines
		
	
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1290 lines
		
	
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (c) 2015, 2023, Oracle and/or its affiliates.
 | |
|    Copyright (c) 2020, MariaDB Corporation.
 | |
| 
 | |
|   This program is free software; you can redistribute it and/or modify
 | |
|   it under the terms of the GNU General Public License, version 2.0,
 | |
|   as published by the Free Software Foundation.
 | |
| 
 | |
|   This program is also distributed with certain software (including
 | |
|   but not limited to OpenSSL) that is licensed under separate terms,
 | |
|   as designated in a particular file or component or in included license
 | |
|   documentation.  The authors of MySQL hereby grant you an additional
 | |
|   permission to link the program and your derivative works with the
 | |
|   separately licensed software that they have included with MySQL.
 | |
| 
 | |
|   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, version 2.0, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
 | |
| 
 | |
| /**
 | |
|   @file storage/perfschema/pfs_variable.cc
 | |
|   Performance schema system variable and status variable (implementation).
 | |
| */
 | |
| #include "sql_plugin.h"
 | |
| #include "pfs_variable.h"
 | |
| #include "my_sys.h"
 | |
| #include "debug_sync.h"
 | |
| #include "pfs.h"
 | |
| #include "pfs_global.h"
 | |
| #include "pfs_visitor.h"
 | |
| #include "sql_audit.h"                      // audit_global_variable_get
 | |
| 
 | |
| static inline SHOW_SCOPE show_scope_from_type(enum enum_mysql_show_type type)
 | |
| {
 | |
|   switch(type) {
 | |
|     case SHOW_BOOL:
 | |
|     case SHOW_CHAR:
 | |
|     case SHOW_CHAR_PTR:
 | |
|     case SHOW_DOUBLE:
 | |
|     case SHOW_HAVE:
 | |
|     case SHOW_HA_ROWS:
 | |
|     case SHOW_KEY_CACHE_LONG:
 | |
|     case SHOW_LEX_STRING:
 | |
|     case SHOW_LONG_NOFLUSH:
 | |
|     case SHOW_MY_BOOL:
 | |
|     case SHOW_SINT:
 | |
|     case SHOW_SLONG:
 | |
|     case SHOW_SLONGLONG:
 | |
|     case SHOW_SYS:
 | |
|     case SHOW_UINT:
 | |
|     case SHOW_ULONG:
 | |
|     case SHOW_ULONGLONG:
 | |
|     case SHOW_LONGLONG_NOFLUSH:
 | |
|       return SHOW_SCOPE_GLOBAL;
 | |
| 
 | |
|     case SHOW_DOUBLE_STATUS:
 | |
|     case SHOW_LONGLONG_STATUS:
 | |
|     case SHOW_LONG_STATUS:
 | |
|       return SHOW_SCOPE_ALL;
 | |
| 
 | |
|     case SHOW_ARRAY:
 | |
|     case SHOW_FUNC:
 | |
|     case SHOW_SIMPLE_FUNC:
 | |
|     case SHOW_UNDEF:
 | |
|     default:
 | |
|       return SHOW_SCOPE_ALL;
 | |
|   }
 | |
|   return SHOW_SCOPE_UNDEF;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   CLASS PFS_system_variable_cache
 | |
| */
 | |
| 
 | |
| /**
 | |
|   Build a sorted list of all system variables from the system variable hash.
 | |
|   Filter by scope. Must be called inside of LOCK_plugin_delete.
 | |
| */
 | |
| bool PFS_system_variable_cache::init_show_var_array(enum_var_type scope, bool strict)
 | |
| {
 | |
|   assert(!m_initialized);
 | |
|   m_query_scope= scope;
 | |
| 
 | |
|   mysql_prlock_rdlock(&LOCK_system_variables_hash);
 | |
|   DEBUG_SYNC(m_current_thd, "acquired_LOCK_system_variables_hash");
 | |
| 
 | |
|   /* Record the system variable hash version to detect subsequent changes. */
 | |
|   m_version= get_system_variable_hash_version();
 | |
| 
 | |
|   /* Build the SHOW_VAR array from the system variable hash. */
 | |
|   SHOW_VAR *vars= enumerate_sys_vars(m_current_thd, true, m_query_scope/*, strict */);
 | |
|   m_show_var_array.reserve(get_system_variable_hash_records());
 | |
|   for (int i=0; vars[i].name; i++)
 | |
|     m_show_var_array.set(i, vars[i]);
 | |
| 
 | |
|   mysql_prlock_unlock(&LOCK_system_variables_hash);
 | |
| 
 | |
|   /* Increase cache size if necessary. */
 | |
|   m_cache.reserve(m_show_var_array.elements());
 | |
| 
 | |
|   m_initialized= true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build an array of SHOW_VARs from the system variable hash.
 | |
|   Filter for SESSION scope.
 | |
| */
 | |
| bool PFS_system_variable_cache::do_initialize_session(void)
 | |
| {
 | |
|   /* Block plugins from unloading. */
 | |
|   mysql_mutex_lock(&LOCK_plugin_delete);
 | |
| 
 | |
|   /* Build the array. */
 | |
|   bool ret= init_show_var_array(OPT_SESSION, true);
 | |
| 
 | |
|   mysql_mutex_unlock(&LOCK_plugin_delete);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Match system variable scope to desired scope.
 | |
| */
 | |
| bool PFS_system_variable_cache::match_scope(int scope)
 | |
| {
 | |
|   switch (scope)
 | |
|   {
 | |
|     case sys_var::GLOBAL:
 | |
|       return m_query_scope == OPT_GLOBAL;
 | |
|       break;
 | |
| 
 | |
|     case sys_var::SESSION:
 | |
|       return (m_query_scope == OPT_GLOBAL || m_query_scope == OPT_SESSION);
 | |
|       break;
 | |
| 
 | |
|     case sys_var::ONLY_SESSION:
 | |
|       return m_query_scope == OPT_SESSION;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|       break;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build a GLOBAL system variable cache.
 | |
| */
 | |
| int PFS_system_variable_cache::do_materialize_global(void)
 | |
| {
 | |
|   /* Block system variable additions or deletions. */
 | |
|   mysql_mutex_lock(&LOCK_global_system_variables);
 | |
| 
 | |
|   m_materialized= false;
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from system variable hash. Do this within
 | |
|      LOCK_plugin_delete to ensure that the hash table remains unchanged
 | |
|      during materialization.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_GLOBAL, true);
 | |
| 
 | |
|   /* Resolve the value for each SHOW_VAR in the array, add to cache. */
 | |
|   for (SHOW_VAR *show_var= m_show_var_array.front();
 | |
|        show_var->value && (show_var != m_show_var_array.end()); show_var++)
 | |
|   {
 | |
|     const Lex_ident_sys_var name= Lex_cstring_strlen(show_var->name);
 | |
|     sys_var *value= (sys_var *)show_var->value;
 | |
|     assert(value);
 | |
| 
 | |
|     if ((m_query_scope == OPT_GLOBAL) &&
 | |
|         name.streq("sql_log_bin"_LEX_CSTRING))
 | |
|     {
 | |
|       /*
 | |
|         PLEASE READ:
 | |
|         http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-6.html
 | |
| 
 | |
|         SQL_LOG_BIN is:
 | |
|         - declared in sys_vars.cc as both GLOBAL and SESSION in 5.7
 | |
|         - impossible to SET with SET GLOBAL (raises an error)
 | |
|         - and yet can be read with @@global.sql_log_bin
 | |
| 
 | |
|         When show_compatibility_56 = ON,
 | |
|         - SHOW GLOBAL VARIABLES does expose a row for SQL_LOG_BIN
 | |
|         - INFORMATION_SCHEMA.GLOBAL_VARIABLES also does expose a row,
 | |
|         both are for backward compatibility of existing applications,
 | |
|         so that no application logic change is required.
 | |
| 
 | |
|         Now, with show_compatibility_56 = OFF (aka, in this code)
 | |
|         - SHOW GLOBAL VARIABLES does -- not -- expose a row for SQL_LOG_BIN
 | |
|         - PERFORMANCE_SCHEMA.GLOBAL_VARIABLES also does -- not -- expose a row
 | |
|         so that a clean interface is exposed to (upgraded and modified) applications.
 | |
| 
 | |
|         The assert below will fail once SQL_LOG_BIN really is defined
 | |
|         as SESSION_ONLY (in 5.8), so that this special case can be removed.
 | |
|       */
 | |
|       assert(value->scope() == sys_var::SESSION);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     /* Match the system variable scope to the target scope. */
 | |
|     if (match_scope(value->scope()))
 | |
|     {
 | |
|       /* Resolve value, convert to text, add to cache. */
 | |
|       System_variable system_var(m_current_thd, show_var, m_query_scope, false);
 | |
|       m_cache.push(system_var);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   m_materialized= true;
 | |
|   mysql_mutex_unlock(&LOCK_global_system_variables);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build a GLOBAL and SESSION system variable cache.
 | |
| */
 | |
| int PFS_system_variable_cache::do_materialize_all(THD *unsafe_thd)
 | |
| {
 | |
|   int ret= 1;
 | |
| 
 | |
|   m_unsafe_thd= unsafe_thd;
 | |
|   m_safe_thd= NULL;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Block plugins from unloading. */
 | |
|   mysql_mutex_lock(&LOCK_plugin_delete);
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from system variable hash. Do this within
 | |
|      LOCK_plugin_delete to ensure that the hash table remains unchanged
 | |
|      while this thread is materialized.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_SESSION, false);
 | |
| 
 | |
|   /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(unsafe_thd)) != NULL)
 | |
|   {
 | |
|     DEBUG_SYNC(m_current_thd, "materialize_session_variable_array_THD_locked");
 | |
|     for (SHOW_VAR *show_var= m_show_var_array.front();
 | |
|          show_var->value && (show_var != m_show_var_array.end()); show_var++)
 | |
|     {
 | |
|       /* Resolve value, convert to text, add to cache. */
 | |
|       System_variable system_var(m_safe_thd, show_var, m_query_scope, false);
 | |
|       m_cache.push(system_var);
 | |
|     }
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_mutex_unlock(&LOCK_plugin_delete);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocate and assign mem_root for system variable materialization.
 | |
| */
 | |
| void PFS_system_variable_cache::set_mem_root(void)
 | |
| {
 | |
|   if (m_mem_sysvar_ptr == NULL)
 | |
|   {
 | |
|     init_sql_alloc(PSI_INSTRUMENT_ME, &m_mem_sysvar, SYSVAR_MEMROOT_BLOCK_SIZE, 0, 0);
 | |
|     m_mem_sysvar_ptr= &m_mem_sysvar;
 | |
|   }
 | |
|   m_mem_thd= ¤t_thd->mem_root;      /* pointer to current THD mem_root */
 | |
|   m_mem_thd_save= *m_mem_thd;             /* restore later */
 | |
|   *m_mem_thd= &m_mem_sysvar;              /* use temporary mem_root */
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Mark memory blocks in the temporary mem_root as free.
 | |
|   Restore THD::mem_root.
 | |
| */
 | |
| void PFS_system_variable_cache::clear_mem_root(void)
 | |
| {
 | |
|   if (m_mem_sysvar_ptr)
 | |
|   {
 | |
|     free_root(&m_mem_sysvar, MYF(MY_MARK_BLOCKS_FREE));
 | |
|     *m_mem_thd= m_mem_thd_save;          /* restore original mem_root */
 | |
|     m_mem_thd= NULL;
 | |
|     m_mem_thd_save= NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free the temporary mem_root.
 | |
|   Restore THD::mem_root if necessary.
 | |
| */
 | |
| void PFS_system_variable_cache::free_mem_root(void)
 | |
| {
 | |
|   if (m_mem_sysvar_ptr)
 | |
|   {
 | |
|     free_root(&m_mem_sysvar, MYF(0));
 | |
|     m_mem_sysvar_ptr= NULL;
 | |
|     if (m_mem_thd && m_mem_thd_save)
 | |
|     {
 | |
|       *m_mem_thd= m_mem_thd_save;       /* restore original mem_root */
 | |
|       m_mem_thd= NULL;
 | |
|       m_mem_thd_save= NULL;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build a SESSION system variable cache for a pfs_thread.
 | |
|   Requires that init_show_var_array() has already been called.
 | |
|   Return 0 for success.
 | |
| */
 | |
| int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread)
 | |
| {
 | |
|   int ret= 1;
 | |
| 
 | |
|   m_pfs_thread= pfs_thread;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Block plugins from unloading. */
 | |
|   mysql_mutex_lock(&LOCK_plugin_delete);
 | |
| 
 | |
|   /* The SHOW_VAR array must be initialized externally. */
 | |
|   assert(m_initialized);
 | |
| 
 | |
|   /* Use a temporary mem_root to avoid depleting THD mem_root. */
 | |
|   if (m_use_mem_root)
 | |
|     set_mem_root();
 | |
| 
 | |
|   /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(pfs_thread)) != NULL)
 | |
|   {
 | |
|     for (SHOW_VAR *show_var= m_show_var_array.front();
 | |
|          show_var->value && (show_var != m_show_var_array.end()); show_var++)
 | |
|     {
 | |
|       sys_var *value= (sys_var *)show_var->value;
 | |
| 
 | |
|       /* Match the system variable scope to the target scope. */
 | |
|       if (match_scope(value->scope()))
 | |
|       {
 | |
|         /* Resolve value, convert to text, add to cache. */
 | |
|         System_variable system_var(m_safe_thd, show_var, m_query_scope, false);
 | |
|         m_cache.push(system_var);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   /* Mark mem_root blocks as free. */
 | |
|   if (m_use_mem_root)
 | |
|     clear_mem_root();
 | |
| 
 | |
|   mysql_mutex_unlock(&LOCK_plugin_delete);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Materialize a single system variable for a pfs_thread.
 | |
|   Requires that init_show_var_array() has already been called.
 | |
|   Return 0 for success.
 | |
| */
 | |
| int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread, uint index)
 | |
| {
 | |
|   int ret= 1;
 | |
| 
 | |
|   m_pfs_thread= pfs_thread;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Block plugins from unloading. */
 | |
|   mysql_mutex_lock(&LOCK_plugin_delete);
 | |
| 
 | |
|   /* The SHOW_VAR array must be initialized externally. */
 | |
|   assert(m_initialized);
 | |
| 
 | |
|   /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(pfs_thread)) != NULL)
 | |
|   {
 | |
|     SHOW_VAR *show_var= &m_show_var_array.at(index);
 | |
| 
 | |
|     if (show_var && show_var->value &&
 | |
|         (show_var != m_show_var_array.end()))
 | |
|     {
 | |
|       sys_var *value= (sys_var *)show_var->value;
 | |
| 
 | |
|       /* Match the system variable scope to the target scope. */
 | |
|       if (match_scope(value->scope()))
 | |
|       {
 | |
|         /* Resolve value, convert to text, add to cache. */
 | |
|         System_variable system_var(m_safe_thd, show_var, m_query_scope, false);
 | |
|         m_cache.push(system_var);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_mutex_unlock(&LOCK_plugin_delete);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build a SESSION system variable cache for a THD.
 | |
| */
 | |
| int PFS_system_variable_cache::do_materialize_session(THD *unsafe_thd)
 | |
| {
 | |
|   int ret= 1;
 | |
| 
 | |
|   m_unsafe_thd= unsafe_thd;
 | |
|   m_safe_thd= NULL;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Block plugins from unloading. */
 | |
|   mysql_mutex_lock(&LOCK_plugin_delete);
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from system variable hash. Do this within
 | |
|      LOCK_plugin_delete to ensure that the hash table remains unchanged
 | |
|      while this thread is materialized.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_SESSION, true);
 | |
| 
 | |
|   /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(unsafe_thd)) != NULL)
 | |
|   {
 | |
|     for (SHOW_VAR *show_var= m_show_var_array.front();
 | |
|          show_var->value && (show_var != m_show_var_array.end()); show_var++)
 | |
|     {
 | |
|       sys_var *value = (sys_var *)show_var->value;
 | |
| 
 | |
|       /* Match the system variable scope to the target scope. */
 | |
|       if (match_scope(value->scope()))
 | |
|       {
 | |
|         /* Resolve value, convert to text, add to cache. */
 | |
|         System_variable system_var(m_safe_thd, show_var, m_query_scope, false);
 | |
|         m_cache.push(system_var);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_mutex_unlock(&LOCK_plugin_delete);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   CLASS System_variable
 | |
| */
 | |
| 
 | |
| /**
 | |
|   Empty placeholder.
 | |
| */
 | |
| System_variable::System_variable()
 | |
|   : m_name(NULL), m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF), m_scope(0),
 | |
|     m_ignore(false), m_charset(NULL), m_initialized(false)
 | |
| {
 | |
|   m_value_str[0]= '\0';
 | |
| }
 | |
| 
 | |
| /**
 | |
|   GLOBAL or SESSION system variable.
 | |
| */
 | |
| System_variable::System_variable(THD *target_thd, const SHOW_VAR *show_var,
 | |
|                                  enum_var_type query_scope, bool ignore)
 | |
|   : m_name(NULL), m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF), m_scope(0),
 | |
|     m_ignore(ignore), m_charset(NULL), m_initialized(false)
 | |
| {
 | |
|   init(target_thd, show_var, query_scope);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get sys_var value from global or local source then convert to string.
 | |
| */
 | |
| void System_variable::init(THD *target_thd, const SHOW_VAR *show_var,
 | |
|                            enum_var_type query_scope)
 | |
| {
 | |
|   if (show_var == NULL || show_var->name == NULL)
 | |
|     return;
 | |
| 
 | |
|   DBUG_ASSERT(show_var->type == SHOW_SYS);
 | |
| 
 | |
|   m_name= show_var->name;
 | |
|   m_name_length= strlen(m_name);
 | |
| 
 | |
|   /* Deprecated variables are ignored but must still be accounted for. */
 | |
|   if (m_ignore)
 | |
|   {
 | |
|     m_value_str[0]= '\0';
 | |
|     m_value_length= 0;
 | |
|     m_initialized= true;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   /* Block remote target thread from updating this system variable. */
 | |
|   /*XXX
 | |
|   THD *current_thread= current_thd;
 | |
|   if (target_thd != current_thread)
 | |
|     mysql_mutex_lock(&target_thd->LOCK_thd_sysvar);*/
 | |
| 
 | |
|   sys_var *system_var= (sys_var *)show_var->value;
 | |
|   assert(system_var != NULL);
 | |
|   m_charset= system_var->charset(target_thd);
 | |
|   m_type= system_var->show_type();
 | |
|   m_scope= system_var->scope();
 | |
| 
 | |
|   /* Get the value of the system variable. */
 | |
|   String buf(m_value_str, sizeof(m_value_str) - 1, system_charset_info);
 | |
|   if (!system_var->val_str_nolock(&buf, target_thd,
 | |
|                system_var->value_ptr(target_thd, query_scope, &null_clex_str)))
 | |
|     buf.length(0);
 | |
| 
 | |
|   m_value_length= MY_MIN(buf.length(), SHOW_VAR_FUNC_BUFF_SIZE);
 | |
| 
 | |
|   /* Returned value may reference a string other than m_value_str. */
 | |
|   if (buf.ptr() != m_value_str)
 | |
|     memcpy(m_value_str, buf.ptr(), m_value_length);
 | |
|   m_value_str[m_value_length]= 0;
 | |
| 
 | |
|   /*XXX
 | |
|   if (target_thd != current_thread)
 | |
|     mysql_mutex_unlock(&target_thd->LOCK_thd_sysvar);*/
 | |
| 
 | |
|   m_initialized= true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   CLASS PFS_status_variable_cache
 | |
| */
 | |
| 
 | |
| PFS_status_variable_cache::
 | |
| PFS_status_variable_cache(bool external_init) :
 | |
|                           PFS_variable_cache<Status_variable>(external_init),
 | |
|                           m_show_command(false), m_sum_client_status(NULL)
 | |
| {
 | |
|   /* Determine if the originating query is a SHOW command. */
 | |
|   m_show_command= (m_current_thd->lex->sql_command == SQLCOM_SHOW_STATUS);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build cache of SESSION status variables for a user.
 | |
| */
 | |
| int PFS_status_variable_cache::materialize_user(PFS_user *pfs_user)
 | |
| {
 | |
|   if (!pfs_user)
 | |
|     return 1;
 | |
| 
 | |
|   if (is_materialized(pfs_user))
 | |
|     return 0;
 | |
| 
 | |
|   if (!pfs_user->m_lock.is_populated())
 | |
|     return 1;
 | |
| 
 | |
|   /* Set callback function. */
 | |
|   m_sum_client_status= sum_user_status;
 | |
|   return do_materialize_client((PFS_client *)pfs_user);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build cache of SESSION status variables for a host.
 | |
| */
 | |
| int PFS_status_variable_cache::materialize_host(PFS_host *pfs_host)
 | |
| {
 | |
|   if (!pfs_host)
 | |
|     return 1;
 | |
| 
 | |
|   if (is_materialized(pfs_host))
 | |
|     return 0;
 | |
| 
 | |
|   if (!pfs_host->m_lock.is_populated())
 | |
|     return 1;
 | |
| 
 | |
|   /* Set callback function. */
 | |
|   m_sum_client_status= sum_host_status;
 | |
|   return do_materialize_client((PFS_client *)pfs_host);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build cache of SESSION status variables for an account.
 | |
| */
 | |
| int PFS_status_variable_cache::materialize_account(PFS_account *pfs_account)
 | |
| {
 | |
|   if (!pfs_account)
 | |
|     return 1;
 | |
| 
 | |
|   if (is_materialized(pfs_account))
 | |
|     return 0;
 | |
| 
 | |
|   if (!pfs_account->m_lock.is_populated())
 | |
|     return 1;
 | |
| 
 | |
|   /* Set callback function. */
 | |
|   m_sum_client_status= sum_account_status;
 | |
|   return do_materialize_client((PFS_client *)pfs_account);
 | |
| }
 | |
| /**
 | |
|   Compare status variable scope to desired scope.
 | |
|   @param variable_scope         Scope of current status variable
 | |
|   @return TRUE if variable matches the query scope
 | |
| */
 | |
| bool PFS_status_variable_cache::match_scope(SHOW_SCOPE variable_scope, bool strict)
 | |
| {
 | |
|   switch (variable_scope)
 | |
|   {
 | |
|     case SHOW_SCOPE_GLOBAL:
 | |
|       return (m_query_scope == OPT_GLOBAL) || (! strict && (m_query_scope == OPT_SESSION));
 | |
|       break;
 | |
|     case SHOW_SCOPE_SESSION:
 | |
|       /* Ignore session-only vars if aggregating by user, host or account. */
 | |
|       if (m_aggregate)
 | |
|         return false;
 | |
|       else
 | |
|         return (m_query_scope == OPT_SESSION);
 | |
|       break;
 | |
|     case SHOW_SCOPE_ALL:
 | |
|       return (m_query_scope == OPT_GLOBAL || m_query_scope == OPT_SESSION);
 | |
|       break;
 | |
|     case SHOW_SCOPE_UNDEF:
 | |
|     default:
 | |
|       return false;
 | |
|       break;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Exclude specific status variables from the query by name or prefix.
 | |
|   Return TRUE if variable should be filtered.
 | |
| */
 | |
| bool PFS_status_variable_cache::filter_by_name(const SHOW_VAR *show_var)
 | |
| {
 | |
|   assert(show_var);
 | |
|   assert(show_var->name);
 | |
| 
 | |
|   if (show_var->type == SHOW_ARRAY)
 | |
|   {
 | |
|     /* The SHOW_ARRAY name is the prefix for the variables in the subarray. */
 | |
|     const Lex_ident_sys_var prefix= Lex_cstring_strlen(show_var->name);
 | |
|     /* Exclude COM counters if not a SHOW STATUS command. */
 | |
|     if (prefix.streq("Com"_LEX_CSTRING) && !m_show_command)
 | |
|       return true;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /*
 | |
|       Slave status resides in Performance Schema replication tables. Exclude
 | |
|       these slave status variables from the SHOW STATUS command and from the
 | |
|       status tables.
 | |
|       Assume null prefix to ensure that only server-defined slave status
 | |
|       variables are filtered.
 | |
|     */
 | |
|     const Lex_ident_sys_var name= Lex_cstring_strlen(show_var->name);
 | |
|     if (name.streq("Slave_running"_LEX_CSTRING) ||
 | |
|         name.streq("Slave_retried_transactions"_LEX_CSTRING) ||
 | |
|         name.streq("Slave_last_heartbeat"_LEX_CSTRING) ||
 | |
|         name.streq("Slave_received_heartbeats"_LEX_CSTRING) ||
 | |
|         name.streq("Slave_heartbeat_period"_LEX_CSTRING))
 | |
|     {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check that the variable type is aggregatable.
 | |
| 
 | |
|   @param variable_type         Status variable type
 | |
|   @return TRUE if variable type can be aggregated
 | |
| */
 | |
| bool PFS_status_variable_cache::can_aggregate(enum_mysql_show_type variable_type)
 | |
| {
 | |
|   switch(variable_type)
 | |
|   {
 | |
|     /*
 | |
|       All server status counters that are totaled across threads are defined in
 | |
|       system_status_var as either SHOW_LONGLONG_STATUS or SHOW_LONG_STATUS.
 | |
|       These data types are not available to plugins.
 | |
|     */
 | |
|     case SHOW_LONGLONG_STATUS:
 | |
|     case SHOW_LONG_STATUS:
 | |
|       return true;
 | |
|       break;
 | |
| 
 | |
|     /* Server and plugin */
 | |
|     case SHOW_UNDEF:
 | |
|     case SHOW_BOOL:
 | |
|     case SHOW_CHAR:
 | |
|     case SHOW_CHAR_PTR:
 | |
|     case SHOW_ARRAY:
 | |
|     case SHOW_FUNC:
 | |
|     case SHOW_SIMPLE_FUNC:
 | |
|     case SHOW_INT:
 | |
|     case SHOW_LONG:
 | |
|     case SHOW_LONGLONG:
 | |
|     case SHOW_DOUBLE:
 | |
|     /* Server only */
 | |
|     case SHOW_HAVE:
 | |
|     case SHOW_MY_BOOL:
 | |
|     case SHOW_SYS:
 | |
|     case SHOW_LEX_STRING:
 | |
|     case SHOW_KEY_CACHE_LONG:
 | |
|     case SHOW_DOUBLE_STATUS:
 | |
|     case SHOW_HA_ROWS:
 | |
|     case SHOW_LONG_NOFLUSH:
 | |
|     case SHOW_LONGLONG_NOFLUSH:
 | |
|     case SHOW_SLONG:
 | |
|     default:
 | |
|       return false;
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if a status variable should be excluded from the query.
 | |
|   Return TRUE if the variable should be excluded.
 | |
| */
 | |
| bool PFS_status_variable_cache::filter_show_var(const SHOW_VAR *show_var, bool strict)
 | |
| {
 | |
|   /* Match the variable scope with the query scope. */
 | |
|   if (!match_scope(show_scope_from_type(show_var->type), strict))
 | |
|     return true;
 | |
| 
 | |
|   /* Exclude specific status variables by name or prefix. */
 | |
|   if (filter_by_name(show_var))
 | |
|     return true;
 | |
| 
 | |
|   /* For user, host or account, ignore variables having non-aggregatable types. */
 | |
|   if (m_aggregate && !can_aggregate(show_var->type))
 | |
|     return true;
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Build an array of SHOW_VARs from the global status array. Expand nested
 | |
|   subarrays, filter unwanted variables.
 | |
|   NOTE: Must be done under LOCK_all_status_vars
 | |
| */
 | |
| bool PFS_status_variable_cache::init_show_var_array(enum_var_type scope, bool strict)
 | |
| {
 | |
|   assert(!m_initialized);
 | |
| 
 | |
|   /* Resize if necessary. */
 | |
|   m_show_var_array.reserve(all_status_vars.elements + 1);
 | |
| 
 | |
|   m_query_scope= scope;
 | |
| 
 | |
|   for (SHOW_VAR *show_var_iter= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
 | |
|        show_var_iter != dynamic_element(&all_status_vars, all_status_vars.elements, SHOW_VAR *);
 | |
|        show_var_iter++)
 | |
|   {
 | |
|     SHOW_VAR show_var= *show_var_iter;
 | |
| 
 | |
|     /* Check if this status var should be excluded from the query. */
 | |
|     if (filter_show_var(&show_var, strict))
 | |
|       continue;
 | |
| 
 | |
|     if (show_var.type == SHOW_ARRAY)
 | |
|     {
 | |
|       /* Expand nested subarray. The name is used as a prefix. */
 | |
|       expand_show_var_array((SHOW_VAR *)show_var.value, show_var.name, strict);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       show_var.name= make_show_var_name(NULL, show_var.name);
 | |
|       m_show_var_array.push(show_var);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Last element is NULL. */
 | |
|   st_mysql_show_var empty= {0,0,SHOW_UNDEF};
 | |
|   m_show_var_array.push(empty);
 | |
| 
 | |
|   /* Get the latest version of all_status_vars. */
 | |
|   m_version= get_status_vars_version();
 | |
| 
 | |
|   /* Increase cache size if necessary. */
 | |
|   m_cache.reserve(m_show_var_array.elements());
 | |
| 
 | |
|   m_initialized= true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Expand a nested subarray of status variables, indicated by a type of SHOW_ARRAY.
 | |
| */
 | |
| void PFS_status_variable_cache::expand_show_var_array(const SHOW_VAR *show_var_array, const char *prefix, bool strict)
 | |
| {
 | |
|   for (const SHOW_VAR *show_var_ptr= show_var_array;
 | |
|        show_var_ptr && show_var_ptr->name;
 | |
|        show_var_ptr++)
 | |
|   {
 | |
|     SHOW_VAR show_var= *show_var_ptr;
 | |
| 
 | |
|     if (filter_show_var(&show_var, strict))
 | |
|       continue;
 | |
| 
 | |
|     if (show_var.type == SHOW_ARRAY)
 | |
|     {
 | |
|       char name_buf[SHOW_VAR_MAX_NAME_LEN];
 | |
|       show_var.name= make_show_var_name(prefix, show_var.name, name_buf, sizeof(name_buf));
 | |
|       /* Expand nested subarray. The name is used as a prefix. */
 | |
|       expand_show_var_array((SHOW_VAR *)show_var.value, show_var.name, strict);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Add the SHOW_VAR element. Make a local copy of the name string. */
 | |
|       show_var.name= make_show_var_name(prefix, show_var.name);
 | |
|       m_show_var_array.push(show_var);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build the complete status variable name, with prefix. Return in buffer provided.
 | |
| */
 | |
| char * PFS_status_variable_cache::make_show_var_name(const char* prefix, const char* name,
 | |
|                                                      char *name_buf, size_t buf_len)
 | |
| {
 | |
|   assert(name_buf != NULL);
 | |
|   char *prefix_end= name_buf;
 | |
| 
 | |
|   if (prefix && *prefix)
 | |
|   {
 | |
|     /* Drop the prefix into the front of the name buffer. */
 | |
|     prefix_end= my_stpnmov(name_buf, prefix, buf_len-1);
 | |
|     *prefix_end++= '_';
 | |
|   }
 | |
| 
 | |
|   /* Restrict name length to remaining buffer size. */
 | |
|   size_t max_name_len= name_buf + buf_len - prefix_end;
 | |
| 
 | |
|   /* Load the name into the buffer after the prefix. */
 | |
|   my_stpnmov(prefix_end, name, max_name_len);
 | |
|   name_buf[buf_len-1]= 0;
 | |
| 
 | |
|   return (name_buf);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Make a copy of the name string prefixed with the subarray name if necessary.
 | |
| */
 | |
| char * PFS_status_variable_cache::make_show_var_name(const char* prefix, const char* name)
 | |
| {
 | |
|   char name_buf[SHOW_VAR_MAX_NAME_LEN];
 | |
|   size_t buf_len= sizeof(name_buf);
 | |
|   make_show_var_name(prefix, name, name_buf, buf_len);
 | |
|   return m_current_thd->strdup(name_buf); /* freed at statement end */
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build an internal SHOW_VAR array from the external status variable array.
 | |
| */
 | |
| bool PFS_status_variable_cache::do_initialize_session(void)
 | |
| {
 | |
|   /* Acquire LOCK_all_status_vars to guard against plugin load/unload. */
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   bool ret= init_show_var_array(OPT_SESSION, true);
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   For the current THD, use initial_status_vars taken from before the query start.
 | |
| */
 | |
| STATUS_VAR *PFS_status_variable_cache::set_status_vars(void)
 | |
| {
 | |
|   STATUS_VAR *status_vars;
 | |
|   if (m_safe_thd == m_current_thd && m_current_thd->initial_status_var != NULL)
 | |
|     status_vars= m_current_thd->initial_status_var;
 | |
|   else
 | |
|     status_vars= &m_safe_thd->status_var;
 | |
| 
 | |
|   return status_vars;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build cache for GLOBAL status variables using values totaled from all threads.
 | |
| */
 | |
| int PFS_status_variable_cache::do_materialize_global(void)
 | |
| {
 | |
|   STATUS_VAR status_totals;
 | |
| 
 | |
|   m_materialized= false;
 | |
|   DEBUG_SYNC(m_current_thd, "before_materialize_global_status_array");
 | |
| 
 | |
|   /* Acquire LOCK_all_status_vars to guard against plugin load/unload. */
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from global status array. Do this under
 | |
|      LOCK_all_status_vars to ensure that the array remains unchanged during
 | |
|      materialization.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_GLOBAL, true);
 | |
| 
 | |
|   /*
 | |
|     Collect totals for all active threads. Start with global status vars as a
 | |
|     baseline.
 | |
|   */
 | |
|   PFS_connection_status_visitor visitor(&status_totals);
 | |
|   PFS_connection_iterator::visit_global(false, /* hosts */
 | |
|                                         false, /* users */
 | |
|                                         false, /* accounts */
 | |
|                                         false, /* threads */
 | |
|                                         true,  /* THDs */
 | |
|                                         &visitor);
 | |
|   /*
 | |
|     Build the status variable cache using the SHOW_VAR array as a reference.
 | |
|     Use the status totals collected from all threads.
 | |
|   */
 | |
|   manifest(m_current_thd, m_show_var_array.front(), &status_totals, "", false, true);
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   m_materialized= true;
 | |
|   DEBUG_SYNC(m_current_thd, "after_materialize_global_status_array");
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build GLOBAL and SESSION status variable cache using values for a non-instrumented thread.
 | |
| */
 | |
| int PFS_status_variable_cache::do_materialize_all(THD* unsafe_thd)
 | |
| {
 | |
|   int ret= 1;
 | |
|   assert(unsafe_thd != NULL);
 | |
| 
 | |
|   m_unsafe_thd= unsafe_thd;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from global status array. Do this under
 | |
|      LOCK_all_status_vars to ensure that the array remains unchanged while this
 | |
|      thread is materialized.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_SESSION, false);
 | |
| 
 | |
|     /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(unsafe_thd)) != NULL)
 | |
|   {
 | |
|     /*
 | |
|       Build the status variable cache using the SHOW_VAR array as a reference.
 | |
|       Use the status values from the THD protected by the thread manager lock.
 | |
|     */
 | |
|     STATUS_VAR *status_vars= set_status_vars();
 | |
|     manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, false);
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build SESSION status variable cache using values for a non-instrumented thread.
 | |
| */
 | |
| int PFS_status_variable_cache::do_materialize_session(THD* unsafe_thd)
 | |
| {
 | |
|   int ret= 1;
 | |
|   assert(unsafe_thd != NULL);
 | |
| 
 | |
|   m_unsafe_thd= unsafe_thd;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   /*
 | |
|      Build array of SHOW_VARs from global status array. Do this under
 | |
|      LOCK_all_status_vars to ensure that the array remains unchanged while this
 | |
|      thread is materialized.
 | |
|    */
 | |
|   if (!m_external_init)
 | |
|     init_show_var_array(OPT_SESSION, true);
 | |
| 
 | |
|     /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(unsafe_thd)) != NULL)
 | |
|   {
 | |
|     /*
 | |
|       Build the status variable cache using the SHOW_VAR array as a reference.
 | |
|       Use the status values from the THD protected by the thread manager lock.
 | |
|     */
 | |
|     STATUS_VAR *status_vars= set_status_vars();
 | |
|     manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true);
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build SESSION status variable cache using values for a PFS_thread.
 | |
|   NOTE: Requires that init_show_var_array() has already been called.
 | |
| */
 | |
| int PFS_status_variable_cache::do_materialize_session(PFS_thread *pfs_thread)
 | |
| {
 | |
|   int ret= 1;
 | |
|   assert(pfs_thread != NULL);
 | |
| 
 | |
|   m_pfs_thread= pfs_thread;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Acquire LOCK_all_status_vars to guard against plugin load/unload. */
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   /* The SHOW_VAR array must be initialized externally. */
 | |
|   assert(m_initialized);
 | |
| 
 | |
|     /* Get and lock a validated THD from the thread manager. */
 | |
|   if ((m_safe_thd= get_THD(pfs_thread)) != NULL)
 | |
|   {
 | |
|     /*
 | |
|       Build the status variable cache using the SHOW_VAR array as a reference.
 | |
|       Use the status values from the THD protected by the thread manager lock.
 | |
|     */
 | |
|     STATUS_VAR *status_vars= set_status_vars();
 | |
|     manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true);
 | |
| 
 | |
|     /* Release lock taken in get_THD(). */
 | |
|     if (m_safe_thd != current_thd)
 | |
|       mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
 | |
| 
 | |
|     m_materialized= true;
 | |
|     ret= 0;
 | |
|   }
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build cache of SESSION status variables using the status values provided.
 | |
|   The cache is associated with a user, host or account, but not with any
 | |
|   particular thread.
 | |
|   NOTE: Requires that init_show_var_array() has already been called.
 | |
| */
 | |
| int PFS_status_variable_cache::do_materialize_client(PFS_client *pfs_client)
 | |
| {
 | |
|   assert(pfs_client != NULL);
 | |
|   STATUS_VAR status_totals;
 | |
| 
 | |
|   m_pfs_client= pfs_client;
 | |
|   m_materialized= false;
 | |
|   m_cache.clear();
 | |
| 
 | |
|   /* Acquire LOCK_all_status_vars to guard against plugin load/unload. */
 | |
|   mysql_rwlock_rdlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   /* The SHOW_VAR array must be initialized externally. */
 | |
|   assert(m_initialized);
 | |
| 
 | |
|   /*
 | |
|     Generate status totals from active threads and from totals aggregated
 | |
|     from disconnected threads.
 | |
|   */
 | |
|   m_sum_client_status(pfs_client, &status_totals);
 | |
| 
 | |
|   /*
 | |
|     Build the status variable cache using the SHOW_VAR array as a reference and
 | |
|     the status totals collected from threads associated with this client.
 | |
|   */
 | |
|   manifest(m_current_thd, m_show_var_array.front(), &status_totals, "", false, true);
 | |
| 
 | |
|   mysql_rwlock_unlock(&LOCK_all_status_vars);
 | |
| 
 | |
|   m_materialized= true;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Build the status variable cache from the expanded and sorted SHOW_VAR array.
 | |
|   Resolve status values using the STATUS_VAR struct provided.
 | |
| */
 | |
| void PFS_status_variable_cache::manifest(THD *thd, const SHOW_VAR *show_var_array,
 | |
|                                     STATUS_VAR *status_vars, const char *prefix,
 | |
|                                     bool nested_array, bool strict)
 | |
| {
 | |
|   for (const SHOW_VAR *show_var_iter= show_var_array;
 | |
|        show_var_iter && show_var_iter->name;
 | |
|        show_var_iter++)
 | |
|   {
 | |
|     // work buffer, must be aligned to handle long/longlong values
 | |
|     my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE+1, MY_ALIGNOF(longlong)>
 | |
|       value_buf;
 | |
|     SHOW_VAR show_var_tmp;
 | |
|     const SHOW_VAR *show_var_ptr= show_var_iter;  /* preserve array pointer */
 | |
| 
 | |
|     /*
 | |
|       If the value is a function reference, then execute the function and
 | |
|       reevaluate the new SHOW_TYPE and value. Handle nested case where
 | |
|       SHOW_FUNC resolves to another SHOW_FUNC.
 | |
|     */
 | |
|     if (show_var_ptr->type == SHOW_FUNC || show_var_ptr->type == SHOW_SIMPLE_FUNC)
 | |
|     {
 | |
|       show_var_tmp= *show_var_ptr;
 | |
|       /*
 | |
|         Execute the function reference in show_var_tmp->value, which returns
 | |
|         show_var_tmp with a new type and new value.
 | |
|       */
 | |
|       for (const SHOW_VAR *var= show_var_ptr;
 | |
|            var->type == SHOW_FUNC || var->type == SHOW_SIMPLE_FUNC;
 | |
|            var= &show_var_tmp)
 | |
|       {
 | |
|         ((mysql_show_var_func)(var->value))(thd, &show_var_tmp, value_buf.data,
 | |
|                                             &thd->status_var, m_query_scope);
 | |
|       }
 | |
|       show_var_ptr= &show_var_tmp;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|       If we are expanding a SHOW_ARRAY, filter variables that were not prefiltered by
 | |
|       init_show_var_array().
 | |
|     */
 | |
|     if (nested_array && filter_show_var(show_var_ptr, strict))
 | |
|       continue;
 | |
| 
 | |
|     if (show_var_ptr->type == SHOW_ARRAY)
 | |
|     {
 | |
|       /*
 | |
|         Status variables of type SHOW_ARRAY were expanded and filtered by
 | |
|         init_show_var_array(), except where a SHOW_FUNC resolves into a
 | |
|         SHOW_ARRAY, such as with InnoDB. Recurse to expand the subarray.
 | |
|       */
 | |
|       manifest(thd, (SHOW_VAR *)show_var_ptr->value, status_vars, show_var_ptr->name, true, strict);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Add the materialized status variable to the cache. */
 | |
|       SHOW_VAR show_var= *show_var_ptr;
 | |
|       /*
 | |
|         For nested array expansions, make a copy of the variable name, just as
 | |
|         done in init_show_var_array().
 | |
|       */
 | |
|       if (nested_array)
 | |
|         show_var.name= make_show_var_name(prefix, show_var_ptr->name);
 | |
| 
 | |
|       /* Convert status value to string format. Add to the cache. */
 | |
|       Status_variable status_var(&show_var, status_vars, m_query_scope);
 | |
|       m_cache.push(status_var);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   CLASS Status_variable
 | |
| */
 | |
| Status_variable::Status_variable(const SHOW_VAR *show_var, STATUS_VAR *status_vars, enum_var_type query_scope)
 | |
|   : m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF),
 | |
|     m_charset(NULL), m_initialized(false)
 | |
| {
 | |
|   init(show_var, status_vars, query_scope);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Resolve status value, convert to string.
 | |
|   show_var->value is an offset into status_vars.
 | |
|   NOTE: Assumes LOCK_all_status_vars is held.
 | |
| */
 | |
| void Status_variable::init(const SHOW_VAR *show_var, STATUS_VAR *status_vars, enum_var_type query_scope)
 | |
| {
 | |
|   if (show_var == NULL || show_var->name == NULL)
 | |
|     return;
 | |
|   m_name= show_var->name;
 | |
|   m_name_length= strlen(m_name);
 | |
|   m_type= show_var->type;
 | |
| 
 | |
|   /* Get the value of the status variable. */
 | |
|   const char *value;
 | |
|   value= get_one_variable(current_thd, show_var, query_scope, m_type,
 | |
|                           status_vars, &m_charset, m_value_str, &m_value_length);
 | |
|   m_value_length= MY_MIN(m_value_length, SHOW_VAR_FUNC_BUFF_SIZE);
 | |
|   m_charset= system_charset_info;
 | |
| 
 | |
|   /* Returned value may reference a string other than m_value_str. */
 | |
|   if (value != m_value_str)
 | |
|     memcpy(m_value_str, value, m_value_length);
 | |
|   m_value_str[m_value_length]= 0;
 | |
| 
 | |
|   m_initialized= true;
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Get status totals for this user from active THDs and related accounts.
 | |
| */
 | |
| void sum_user_status(PFS_client *pfs_user, STATUS_VAR *status_totals)
 | |
| {
 | |
|   PFS_connection_status_visitor visitor(status_totals);
 | |
|   PFS_connection_iterator::visit_user((PFS_user *)pfs_user,
 | |
|                                                   true,  /* accounts */
 | |
|                                                   false, /* threads */
 | |
|                                                   true,  /* THDs */
 | |
|                                                   &visitor);
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Get status totals for this host from active THDs and related accounts.
 | |
| */
 | |
| void sum_host_status(PFS_client *pfs_host, STATUS_VAR *status_totals)
 | |
| {
 | |
|   PFS_connection_status_visitor visitor(status_totals);
 | |
|   PFS_connection_iterator::visit_host((PFS_host *)pfs_host,
 | |
|                                                   true,  /* accounts */
 | |
|                                                   false, /* threads */
 | |
|                                                   true,  /* THDs */
 | |
|                                                   &visitor);
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Get status totals for this account from active THDs and from totals aggregated
 | |
|   from disconnected threads.
 | |
| */
 | |
| void sum_account_status(PFS_client *pfs_account, STATUS_VAR *status_totals)
 | |
| {
 | |
|   PFS_connection_status_visitor visitor(status_totals);
 | |
|   PFS_connection_iterator::visit_account((PFS_account *)pfs_account,
 | |
|                                                         false,      /* threads */
 | |
|                                                         true,       /* THDs */
 | |
|                                                         &visitor);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset aggregated status counter stats for account, user and host.
 | |
|   NOTE: Assumes LOCK_all_status_vars is held.
 | |
| */
 | |
| void reset_pfs_status_stats()
 | |
| {
 | |
|   reset_status_by_account();
 | |
|   reset_status_by_user();
 | |
|   reset_status_by_host();
 | |
| }
 | |
| 
 | |
| /** @} */
 | 
