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