1 /* Copyright (c) 2008, 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 Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 #include "table_session_connect.h"
24 #include "field.h"
25 
26 static const TABLE_FIELD_TYPE field_types[]=
27 {
28   {
29     { C_STRING_WITH_LEN("PROCESSLIST_ID") },
30     { C_STRING_WITH_LEN("int(11)") },
31     { NULL, 0}
32   },
33   {
34     { C_STRING_WITH_LEN("ATTR_NAME") },
35     { C_STRING_WITH_LEN("varchar(32)") },
36     { NULL, 0}
37   },
38   {
39     { C_STRING_WITH_LEN("ATTR_VALUE") },
40     { C_STRING_WITH_LEN("varchar(1024)") },
41     { NULL, 0}
42   },
43   {
44     { C_STRING_WITH_LEN("ORDINAL_POSITION") },
45     { C_STRING_WITH_LEN("int(11)") },
46     { NULL, 0}
47   }
48 };
49 
50 TABLE_FIELD_DEF table_session_connect::m_field_def=
51 { 4, field_types };
52 
table_session_connect(const PFS_engine_table_share * share)53 table_session_connect::table_session_connect(const PFS_engine_table_share *share)
54  : cursor_by_thread_connect_attr(share)
55 {
56   if (session_connect_attrs_size_per_thread > 0)
57   {
58     m_copy_session_connect_attrs= (char *) my_malloc(PSI_INSTRUMENT_ME,
59                                              session_connect_attrs_size_per_thread,
60                                              MYF(0));
61   }
62   else
63   {
64     m_copy_session_connect_attrs= NULL;
65   }
66   m_copy_session_connect_attrs_length= 0;
67 }
68 
~table_session_connect()69 table_session_connect::~table_session_connect()
70 {
71   my_free(m_copy_session_connect_attrs);
72 }
73 
74 /**
75   Take a length encoded string
76 
77   @arg ptr  inout       the input string array
78   @arg dest             where to store the result
79   @arg dest_size        max size of @c dest
80   @arg copied_len       the actual length of the data copied
81   @arg start_ptr        pointer to the start of input
82   @arg input_length     the length of the incoming data
83   @arg copy_data        copy the data or just skip the input
84   @arg from_cs          character set in which @c ptr is encoded
85   @arg nchars_max       maximum number of characters to read
86   @return status
87     @retval true    parsing failed
88     @retval false   parsing succeeded
89 */
parse_length_encoded_string(const char ** ptr,char * dest,uint dest_size,uint * copied_len,const char * start_ptr,uint input_length,bool copy_data,const CHARSET_INFO * from_cs,uint nchars_max)90 bool parse_length_encoded_string(const char **ptr,
91                  char *dest, uint dest_size,
92                  uint *copied_len,
93                  const char *start_ptr, uint input_length,
94                  bool copy_data,
95                  const CHARSET_INFO *from_cs,
96                  uint nchars_max)
97 {
98   ulong copy_length, data_length;
99   const char *well_formed_error_pos= NULL, *cannot_convert_error_pos= NULL,
100         *from_end_pos= NULL;
101 
102   copy_length= data_length= net_field_length((uchar **) ptr);
103 
104   /* we don't tolerate NULL as a length */
105   if (data_length == NULL_LENGTH)
106     return true;
107 
108   if (*ptr - start_ptr + data_length > input_length)
109     return true;
110 
111   copy_length= well_formed_copy_nchars(&my_charset_utf8_bin, dest, dest_size,
112                                        from_cs, *ptr, data_length, nchars_max,
113                                        &well_formed_error_pos,
114                                        &cannot_convert_error_pos,
115                                        &from_end_pos);
116   *copied_len= copy_length;
117   (*ptr)+= data_length;
118 
119   return false;
120 }
121 
122 /**
123   Take the nth attribute name/value pair
124 
125   Parse the attributes blob form the beginning, skipping the attributes
126   whose number is lower than the one we seek.
127   When we reach the attribute at an index we're looking for the values
128   are copied to the output parameters.
129   If parsing fails or no more attributes are found the function stops
130   and returns an error code.
131 
132   @arg connect_attrs            pointer to the connect attributes blob
133   @arg connect_attrs_length     length of @c connect_attrs
134   @arg connect_attrs_cs         character set used to encode @c connect_attrs
135   @arg ordinal                  index of the attribute we need
136   @arg attr_name [out]          buffer to receive the attribute name
137   @arg max_attr_name            max size of @c attr_name in bytes
138   @arg attr_name_length [out]   number of bytes written in @attr_name
139   @arg attr_value [out]         buffer to receive the attribute name
140   @arg max_attr_value           max size of @c attr_value in bytes
141   @arg attr_value_length [out]  number of bytes written in @attr_value
142   @return status
143     @retval true    requested attribute pair is found and copied
144     @retval false   error. Either because of parsing or too few attributes.
145 */
read_nth_attr(const char * connect_attrs,uint connect_attrs_length,const CHARSET_INFO * connect_attrs_cs,uint ordinal,char * attr_name,uint max_attr_name,uint * attr_name_length,char * attr_value,uint max_attr_value,uint * attr_value_length)146 bool read_nth_attr(const char *connect_attrs,
147                    uint connect_attrs_length,
148                    const CHARSET_INFO *connect_attrs_cs,
149                    uint ordinal,
150                    char *attr_name, uint max_attr_name,
151                    uint *attr_name_length,
152                    char *attr_value, uint max_attr_value,
153                    uint *attr_value_length)
154 {
155   uint idx;
156   const char *ptr;
157 
158   for (ptr= connect_attrs, idx= 0;
159        (uint)(ptr - connect_attrs) < connect_attrs_length && idx <= ordinal;
160       idx++)
161   {
162     uint copy_length;
163     /* do the copying only if we absolutely have to */
164     bool fill_in_attr_name= idx == ordinal;
165     bool fill_in_attr_value= idx == ordinal;
166 
167     /* read the key */
168     if (parse_length_encoded_string(&ptr,
169                                     attr_name, max_attr_name, &copy_length,
170                                     connect_attrs,
171                                     connect_attrs_length,
172                                     fill_in_attr_name,
173                                     connect_attrs_cs, 32) ||
174         !copy_length
175         )
176       return false;
177 
178     if (idx == ordinal)
179       *attr_name_length= copy_length;
180 
181     /* read the value */
182     if (parse_length_encoded_string(&ptr,
183                                     attr_value, max_attr_value, &copy_length,
184                                     connect_attrs,
185                                     connect_attrs_length,
186                                     fill_in_attr_value,
187                                     connect_attrs_cs, 1024))
188       return false;
189 
190     if (idx == ordinal)
191       *attr_value_length= copy_length;
192 
193     if (idx == ordinal)
194       return true;
195   }
196 
197   return false;
198 }
199 
make_row(PFS_thread * pfs,uint ordinal)200 void table_session_connect::make_row(PFS_thread *pfs, uint ordinal)
201 {
202   pfs_optimistic_state lock;
203   pfs_optimistic_state session_lock;
204   PFS_thread_class *safe_class;
205   const CHARSET_INFO *cs;
206 
207   m_row_exists= false;
208 
209   /* Protect this reader against thread termination */
210   pfs->m_lock.begin_optimistic_lock(&lock);
211   /* Protect this reader against writing on session attributes */
212   pfs->m_session_lock.begin_optimistic_lock(&session_lock);
213 
214   safe_class= sanitize_thread_class(pfs->m_class);
215   if (unlikely(safe_class == NULL))
216     return;
217 
218   /* Filtering threads must be done under the protection of the optimistic lock. */
219   if (! thread_fits(pfs))
220     return;
221 
222   /* Make a safe copy of the session attributes */
223 
224   if (m_copy_session_connect_attrs == NULL)
225     return;
226 
227   m_copy_session_connect_attrs_length= pfs->m_session_connect_attrs_length;
228 
229   if (m_copy_session_connect_attrs_length > session_connect_attrs_size_per_thread)
230     return;
231 
232   memcpy(m_copy_session_connect_attrs,
233          pfs->m_session_connect_attrs,
234          m_copy_session_connect_attrs_length);
235 
236   cs= get_charset(pfs->m_session_connect_attrs_cs_number, MYF(0));
237   if (cs == NULL)
238     return;
239 
240   if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
241     return;
242 
243   if (! pfs->m_lock.end_optimistic_lock(& lock))
244     return;
245 
246   /*
247     Now we have a safe copy of the data,
248     that will not change while parsing it
249   */
250 
251   /* populate the row */
252   if (read_nth_attr(m_copy_session_connect_attrs,
253                     m_copy_session_connect_attrs_length,
254                     cs,
255                     ordinal,
256                     m_row.m_attr_name, (uint) sizeof(m_row.m_attr_name),
257                     &m_row.m_attr_name_length,
258                     m_row.m_attr_value, (uint) sizeof(m_row.m_attr_value),
259                     &m_row.m_attr_value_length))
260   {
261     /* we don't expect internal threads to have connection attributes */
262     if (pfs->m_processlist_id == 0)
263 	return;
264 
265     m_row.m_ordinal_position= ordinal;
266     m_row.m_process_id= pfs->m_processlist_id;
267 
268     m_row_exists= true;
269   }
270 }
271 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)272 int table_session_connect::read_row_values(TABLE *table,
273                                          unsigned char *buf,
274                                          Field **fields,
275                                          bool read_all)
276 {
277   Field *f;
278 
279   if (unlikely(!m_row_exists))
280     return HA_ERR_RECORD_DELETED;
281 
282   /* Set the null bits */
283   assert(table->s->null_bytes == 1);
284   buf[0]= 0;
285 
286   for (; (f= *fields) ; fields++)
287   {
288     if (read_all || bitmap_is_set(table->read_set, f->field_index))
289     {
290       switch(f->field_index)
291       {
292       case FO_PROCESS_ID:
293         if (m_row.m_process_id != 0)
294           set_field_ulong(f, m_row.m_process_id);
295         else
296           f->set_null();
297         break;
298       case FO_ATTR_NAME:
299         set_field_varchar_utf8(f, m_row.m_attr_name,
300                                m_row.m_attr_name_length);
301         break;
302       case FO_ATTR_VALUE:
303         if (m_row.m_attr_value_length)
304           set_field_varchar_utf8(f, m_row.m_attr_value,
305                                  m_row.m_attr_value_length);
306         else
307           f->set_null();
308         break;
309       case FO_ORDINAL_POSITION:
310         set_field_ulong(f, m_row.m_ordinal_position);
311         break;
312       default:
313         assert(false);
314       }
315     }
316   }
317   return 0;
318 }
319 
320 bool
thread_fits(PFS_thread * thread)321 table_session_connect::thread_fits(PFS_thread *thread)
322 {
323   return true;
324 }
325 
326