1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /**
24   @file storage/perfschema/table_session_variables.cc
25   Table SESSION_VARIABLES (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_session_variables.h"
31 #include "pfs_instr_class.h"
32 #include "pfs_column_types.h"
33 #include "pfs_column_values.h"
34 #include "pfs_global.h"
35 
36 THR_LOCK table_session_variables::m_table_lock;
37 
38 static const TABLE_FIELD_TYPE field_types[]=
39 {
40   {
41     { C_STRING_WITH_LEN("VARIABLE_NAME") },
42     { C_STRING_WITH_LEN("varchar(64)") },
43     { NULL, 0}
44   },
45   {
46     { C_STRING_WITH_LEN("VARIABLE_VALUE") },
47     { C_STRING_WITH_LEN("varchar(1024)") },
48     { NULL, 0}
49   }
50 };
51 
52 TABLE_FIELD_DEF
53 table_session_variables::m_field_def=
54 { 2, field_types };
55 
56 PFS_engine_table_share
57 table_session_variables::m_share=
58 {
59   { C_STRING_WITH_LEN("session_variables") },
60   &pfs_readonly_world_acl,
61   table_session_variables::create,
62   NULL, /* write_row */
63   NULL, /* delete_all_rows */
64   table_session_variables::get_row_count,
65   sizeof(pos_t),
66   &m_table_lock,
67   &m_field_def,
68   false, /* checked */
69   true   /* perpetual */
70 };
71 
72 PFS_engine_table*
create(void)73 table_session_variables::create(void)
74 {
75   return new table_session_variables();
76 }
77 
get_row_count(void)78 ha_rows table_session_variables::get_row_count(void)
79 {
80   mysql_mutex_lock(&LOCK_plugin_delete);
81   mysql_rwlock_rdlock(&LOCK_system_variables_hash);
82   ha_rows system_var_count= get_system_variable_hash_records();
83   mysql_rwlock_unlock(&LOCK_system_variables_hash);
84   mysql_mutex_unlock(&LOCK_plugin_delete);
85   return system_var_count;
86 }
87 
table_session_variables()88 table_session_variables::table_session_variables()
89   : PFS_engine_table(&m_share, &m_pos),
90     m_sysvar_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0)
91 {}
92 
reset_position(void)93 void table_session_variables::reset_position(void)
94 {
95   m_pos.m_index = 0;
96   m_next_pos.m_index = 0;
97 }
98 
rnd_init(bool scan)99 int table_session_variables::rnd_init(bool scan)
100 {
101   /* Build a cache of system variables for this thread. */
102   m_sysvar_cache.materialize_all(current_thd);
103 
104   /* Record the version of the system variable hash. */
105   ulonglong hash_version= m_sysvar_cache.get_sysvar_hash_version();
106 
107   /*
108     The table context holds the current version of the system variable hash.
109     If scan == true, then allocate a new context from mem_root and store in TLS.
110     If scan == false, then restore from TLS.
111   */
112   m_context= (table_session_variables_context *)current_thd->alloc(sizeof(table_session_variables_context));
113   new(m_context) table_session_variables_context(hash_version, !scan);
114   return 0;
115 }
116 
rnd_next(void)117 int table_session_variables::rnd_next(void)
118 {
119   for (m_pos.set_at(&m_next_pos);
120        m_pos.m_index < m_sysvar_cache.size();
121        m_pos.next())
122   {
123     if (m_sysvar_cache.is_materialized())
124     {
125       const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index);
126       if (system_var != NULL)
127       {
128         make_row(system_var);
129         m_next_pos.set_after(&m_pos);
130         return 0;
131       }
132     }
133   }
134   return HA_ERR_END_OF_FILE;
135 }
136 
rnd_pos(const void * pos)137 int table_session_variables::rnd_pos(const void *pos)
138 {
139   /* If system variable hash changes, do nothing. */
140   if (!m_context->versions_match())
141     return HA_ERR_RECORD_DELETED;
142 
143   set_position(pos);
144   assert(m_pos.m_index < m_sysvar_cache.size());
145 
146   if (m_sysvar_cache.is_materialized())
147   {
148     const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index);
149     if (system_var != NULL)
150     {
151       make_row(system_var);
152       return 0;
153     }
154   }
155   return HA_ERR_RECORD_DELETED;
156 }
157 
158 void table_session_variables
make_row(const System_variable * system_var)159 ::make_row(const System_variable *system_var)
160 {
161   m_row_exists= false;
162   if (system_var->is_null() || system_var->is_ignored())
163     return;
164   m_row.m_variable_name.make_row(system_var->m_name, system_var->m_name_length);
165   m_row.m_variable_value.make_row(system_var);
166   m_row_exists= true;
167 }
168 
169 int table_session_variables
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)170 ::read_row_values(TABLE *table,
171                   unsigned char *buf,
172                   Field **fields,
173                   bool read_all)
174 {
175   Field *f;
176 
177   if (unlikely(!m_row_exists))
178     return HA_ERR_RECORD_DELETED;
179 
180   /* Set the null bits */
181   assert(table->s->null_bytes == 1);
182   buf[0]= 0;
183 
184   for (; (f= *fields) ; fields++)
185   {
186     if (read_all || bitmap_is_set(table->read_set, f->field_index))
187     {
188       switch(f->field_index)
189       {
190       case 0: /* VARIABLE_NAME */
191         set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length);
192         break;
193       case 1: /* VARIABLE_VALUE */
194         m_row.m_variable_value.set_field(f);
195         break;
196       default:
197         assert(false);
198       }
199     }
200   }
201 
202   return 0;
203 }
204 
205