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_status.cc
25   Table SESSION_STATUS (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_session_status.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_status::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_status::m_field_def=
54 { 2, field_types };
55 
56 PFS_engine_table_share
57 table_session_status::m_share=
58 {
59   { C_STRING_WITH_LEN("session_status") },
60   &pfs_readonly_world_acl,
61   table_session_status::create,
62   NULL, /* write_row */
63   NULL, /* delete_all_rows */
64   table_session_status::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_status::create(void)
74 {
75   return new table_session_status();
76 }
77 
get_row_count(void)78 ha_rows table_session_status::get_row_count(void)
79 {
80   mysql_mutex_lock(&LOCK_status);
81   ha_rows status_var_count= all_status_vars.size();
82   mysql_mutex_unlock(&LOCK_status);
83   return status_var_count;
84 }
85 
table_session_status()86 table_session_status::table_session_status()
87   : PFS_engine_table(&m_share, &m_pos),
88     m_status_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0)
89 {}
90 
reset_position(void)91 void table_session_status::reset_position(void)
92 {
93   m_pos.m_index = 0;
94   m_next_pos.m_index = 0;
95 }
96 
rnd_init(bool scan)97 int table_session_status::rnd_init(bool scan)
98 {
99  /* Build a cache of all status variables for this thread. */
100   m_status_cache.materialize_all(current_thd);
101 
102   /* Record the current number of status variables to detect subsequent changes. */
103   ulonglong status_version= m_status_cache.get_status_array_version();
104 
105   /*
106     The table context holds the current version of the global status array.
107     If scan == true, then allocate a new context from mem_root and store in TLS.
108     If scan == false, then restore from TLS.
109   */
110   m_context= (table_session_status_context *)current_thd->alloc(sizeof(table_session_status_context));
111   new(m_context) table_session_status_context(status_version, !scan);
112   return 0;
113 }
114 
rnd_next(void)115 int table_session_status::rnd_next(void)
116 {
117   for (m_pos.set_at(&m_next_pos);
118        m_pos.m_index < m_status_cache.size();
119        m_pos.next())
120   {
121     if (m_status_cache.is_materialized())
122     {
123       const Status_variable *stat_var= m_status_cache.get(m_pos.m_index);
124       if (stat_var != NULL)
125       {
126         make_row(stat_var);
127         m_next_pos.set_after(&m_pos);
128         return 0;
129       }
130     }
131   }
132   return HA_ERR_END_OF_FILE;
133 }
134 
135 int
rnd_pos(const void * pos)136 table_session_status::rnd_pos(const void *pos)
137 {
138   /* If global status array has changed, do nothing. */ // TODO: warning
139   if (!m_context->versions_match())
140     return HA_ERR_RECORD_DELETED;
141 
142   set_position(pos);
143   assert(m_pos.m_index < m_status_cache.size());
144 
145   if (m_status_cache.is_materialized())
146   {
147     const Status_variable *stat_var= m_status_cache.get(m_pos.m_index);
148     if (stat_var != NULL)
149     {
150       make_row(stat_var);
151       return 0;
152     }
153   }
154 
155   return HA_ERR_RECORD_DELETED;
156 }
157 
158 void table_session_status
make_row(const Status_variable * status_var)159 ::make_row(const Status_variable *status_var)
160 {
161   m_row_exists= false;
162   m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length);
163   m_row.m_variable_value.make_row(status_var);
164   m_row_exists= true;
165 }
166 
167 int table_session_status
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)168 ::read_row_values(TABLE *table,
169                   unsigned char *buf,
170                   Field **fields,
171                   bool read_all)
172 {
173   Field *f;
174 
175   if (unlikely(!m_row_exists))
176     return HA_ERR_RECORD_DELETED;
177 
178   /* Set the null bits */
179   assert(table->s->null_bytes == 1);
180   buf[0]= 0;
181 
182   for (; (f= *fields) ; fields++)
183   {
184     if (read_all || bitmap_is_set(table->read_set, f->field_index))
185     {
186       switch(f->field_index)
187       {
188       case 0: /* VARIABLE_NAME */
189         set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length);
190         break;
191       case 1: /* VARIABLE_VALUE */
192         m_row.m_variable_value.set_field(f);
193         break;
194       default:
195         assert(false);
196       }
197     }
198   }
199 
200   return 0;
201 }
202 
203