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