1 /* Copyright (c) 2015, 2020, 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, 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 #define LOG_COMPONENT_TAG "test_session_info"
24 
25 #include <fcntl.h>
26 #include <mysql/plugin.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 
30 #include "m_string.h"
31 #include "my_dbug.h"
32 #include "my_inttypes.h"
33 #include "my_io.h"
34 #include "my_psi_config.h"
35 #include "my_sys.h"  // my_write, my_malloc
36 #include "mysql/components/services/psi_thread_bits.h"
37 #include "mysql/psi/mysql_thread.h"
38 #include "mysql_com.h"
39 #include "sql_string.h" /* STRING_PSI_MEMORY_KEY */
40 #include "template_utils.h"
41 #include "violite.h"
42 
43 #include <mysql/components/my_service.h>
44 #include <mysql/components/services/log_builtins.h>
45 #include <mysqld_error.h>
46 
47 static const char *log_filename = "test_session_info";
48 
49 static File outfile;
50 
51 #define STRING_BUFFER_SIZE 1100
52 
53 #define WRITE_STR(format)                                       \
54   {                                                             \
55     snprintf(buffer, sizeof(buffer), "%s", (format));           \
56     my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0)); \
57   }
58 
59 #define WRITE_VAL(format, value)                                \
60   {                                                             \
61     snprintf(buffer, sizeof(buffer), (format), (value));        \
62     my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0)); \
63   }
64 
65 #define WRITE_VAL2(format, value1, value2)                          \
66   {                                                                 \
67     snprintf(buffer, sizeof(buffer), (format), (value1), (value2)); \
68     my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0));     \
69   }
70 
71 static const char *sep =
72     "=========================================================================="
73     "==================\n";
74 
75 #define WRITE_SEP() \
76   my_write(outfile, pointer_cast<const uchar *>(sep), strlen(sep), MYF(0))
77 
78 static SERVICE_TYPE(registry) *reg_srv = nullptr;
79 SERVICE_TYPE(log_builtins) *log_bi = nullptr;
80 SERVICE_TYPE(log_builtins_string) *log_bs = nullptr;
81 
82 static const char *user_localhost = "localhost";
83 static const char *user_local = "127.0.0.1";
84 static const char *user_db = "";
85 static const char *user_privileged = "root";
86 // static const char *user_ordinary= "ordinary";
87 
switch_user(MYSQL_SESSION session,const char * user)88 static void switch_user(MYSQL_SESSION session, const char *user) {
89   MYSQL_SECURITY_CONTEXT sc;
90   thd_get_security_context(srv_session_info_get_thd(session), &sc);
91   security_context_lookup(sc, user, user_localhost, user_local, user_db);
92 }
93 
94 /* Session declarations */
95 COM_DATA cmd;
96 
97 struct st_send_field_n {
98   char db_name[256];
99   char table_name[256];
100   char org_table_name[256];
101   char col_name[256];
102   char org_col_name[256];
103   unsigned long length;
104   unsigned int charsetnr;
105   unsigned int flags;
106   unsigned int decimals;
107   enum_field_types type;
108 };
109 
110 struct st_decimal_n {
111   int intg, frac, len;
112   bool sign;
113   decimal_digit_t buf[256];
114 };
115 
116 struct st_plugin_ctx {
117   const CHARSET_INFO *resultcs;
118   uint meta_server_status;
119   uint meta_warn_count;
120   uint current_col;
121   uint num_cols;
122   uint num_rows;
123   st_send_field_n sql_field[64];
124   char sql_str_value[64][64][256];
125   size_t sql_str_len[64][64];
126   longlong sql_int_value[64][64];
127   longlong sql_longlong_value[64][64];
128   uint sql_is_unsigned[64][64];
129   st_decimal_n sql_decimal_value[64][64];
130   double sql_double_value[64][64];
131   uint32 sql_double_decimals[64][64];
132   MYSQL_TIME sql_date_value[64][64];
133   MYSQL_TIME sql_time_value[64][64];
134   uint sql_time_decimals[64][64];
135   MYSQL_TIME sql_datetime_value[64][64];
136   uint sql_datetime_decimals[64][64];
137 
138   uint server_status;
139   uint warn_count;
140   uint affected_rows;
141   uint last_insert_id;
142   char message[1024];
143 
144   uint sql_errno;
145   char err_msg[1024];
146   char sqlstate[6];
st_plugin_ctxst_plugin_ctx147   st_plugin_ctx() { reset(); }
148 
resetst_plugin_ctx149   void reset() {
150     resultcs = nullptr;
151     server_status = 0;
152     current_col = 0;
153     warn_count = 0;
154     num_cols = 0;
155     num_rows = 0;
156     memset(&sql_field, 0, 64 * sizeof(st_send_field_n));
157     memset(&sql_str_value, 0, 64 * 64 * 256 * sizeof(char));
158     memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
159     memset(&sql_int_value, 0, 64 * 64 * sizeof(longlong));
160     memset(&sql_longlong_value, 0, 64 * 64 * sizeof(longlong));
161     memset(&sql_is_unsigned, 0, 64 * 64 * sizeof(uint));
162     memset(&sql_decimal_value, 0, 64 * 64 * sizeof(st_decimal_n));
163     memset(&sql_double_value, 0, 64 * 64 * sizeof(double));
164     memset(&sql_double_decimals, 0, 64 * 64 * sizeof(uint32));
165     memset(&sql_date_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
166     memset(&sql_time_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
167     memset(&sql_time_decimals, 0, 64 * 64 * sizeof(uint));
168     memset(&sql_datetime_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
169     memset(&sql_datetime_decimals, 0, 64 * 64 * sizeof(uint));
170 
171     server_status = 0;
172     warn_count = 0;
173     affected_rows = 0;
174     last_insert_id = 0;
175     memset(&message, 0, sizeof(message));
176 
177     sql_errno = 0;
178     memset(&err_msg, 0, sizeof(err_msg));
179     memset(&sqlstate, 0, sizeof(sqlstate));
180   }
181 };
182 
sql_start_result_metadata(void * ctx,uint num_cols,uint,const CHARSET_INFO * resultcs)183 static int sql_start_result_metadata(void *ctx, uint num_cols, uint,
184                                      const CHARSET_INFO *resultcs) {
185   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
186   DBUG_TRACE;
187   DBUG_PRINT("info", ("resultcs->number: %d", resultcs->number));
188   DBUG_PRINT("info", ("resultcs->csname: %s", resultcs->csname));
189   DBUG_PRINT("info", ("resultcs->name: %s", resultcs->name));
190   pctx->num_cols = num_cols;
191   pctx->resultcs = resultcs;
192   pctx->current_col = 0;
193   return false;
194 }
195 
sql_field_metadata(void * ctx,struct st_send_field * field,const CHARSET_INFO *)196 static int sql_field_metadata(void *ctx, struct st_send_field *field,
197                               const CHARSET_INFO *) {
198   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
199   st_send_field_n *cfield = &pctx->sql_field[pctx->current_col];
200   DBUG_TRACE;
201   DBUG_PRINT("info", ("field->db_name: %s", field->db_name));
202   DBUG_PRINT("info", ("field->table_name: %s", field->table_name));
203   DBUG_PRINT("info", ("field->org_table_name: %s", field->org_table_name));
204   DBUG_PRINT("info", ("field->col_name: %s", field->col_name));
205   DBUG_PRINT("info", ("field->org_col_name: %s", field->org_col_name));
206   DBUG_PRINT("info", ("field->length: %d", (int)field->length));
207   DBUG_PRINT("info", ("field->charsetnr: %d", (int)field->charsetnr));
208   DBUG_PRINT("info", ("field->flags: %d", (int)field->flags));
209   DBUG_PRINT("info", ("field->decimals: %d", (int)field->decimals));
210   DBUG_PRINT("info", ("field->type: %d", (int)field->type));
211 
212   strcpy(cfield->db_name, field->db_name);
213   strcpy(cfield->table_name, field->table_name);
214   strcpy(cfield->org_table_name, field->org_table_name);
215   strcpy(cfield->col_name, field->col_name);
216   strcpy(cfield->org_col_name, field->org_col_name);
217   cfield->length = field->length;
218   cfield->charsetnr = field->charsetnr;
219   cfield->flags = field->flags;
220   cfield->decimals = field->decimals;
221   cfield->type = field->type;
222 
223   pctx->current_col++;
224   return false;
225 }
226 
sql_end_result_metadata(void * ctx,uint server_status,uint warn_count)227 static int sql_end_result_metadata(void *ctx, uint server_status,
228                                    uint warn_count) {
229   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
230   DBUG_TRACE;
231   pctx->meta_server_status = server_status;
232   pctx->meta_warn_count = warn_count;
233   pctx->num_rows = 0;
234   return false;
235 }
236 
sql_start_row(void * ctx)237 static int sql_start_row(void *ctx) {
238   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
239   DBUG_TRACE;
240   pctx->current_col = 0;
241   return false;
242 }
243 
sql_end_row(void * ctx)244 static int sql_end_row(void *ctx) {
245   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
246   DBUG_TRACE;
247   pctx->num_rows++;
248   return false;
249 }
250 
sql_abort_row(void * ctx)251 static void sql_abort_row(void *ctx) {
252   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
253   DBUG_TRACE;
254   pctx->current_col = 0;
255 }
256 
sql_get_client_capabilities(void *)257 static ulong sql_get_client_capabilities(void *) {
258   DBUG_TRACE;
259   return 0;
260 }
261 
sql_get_null(void * ctx)262 static int sql_get_null(void *ctx) {
263   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
264   DBUG_TRACE;
265   uint row = pctx->num_rows;
266   uint col = pctx->current_col;
267   pctx->current_col++;
268 
269   memcpy(pctx->sql_str_value[row][col], "[NULL]", sizeof("[NULL]"));
270   pctx->sql_str_len[row][col] = sizeof("[NULL]") - 1;
271 
272   return false;
273 }
274 
sql_get_integer(void * ctx,longlong value)275 static int sql_get_integer(void *ctx, longlong value) {
276   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
277   DBUG_TRACE;
278   uint row = pctx->num_rows;
279   uint col = pctx->current_col;
280   pctx->current_col++;
281 
282   size_t len = snprintf(pctx->sql_str_value[row][col],
283                         sizeof(pctx->sql_str_value[row][col]), "%lld", value);
284   pctx->sql_str_len[row][col] = len;
285   pctx->sql_int_value[row][col] = value;
286 
287   return false;
288 }
289 
sql_get_longlong(void * ctx,longlong value,uint is_unsigned)290 static int sql_get_longlong(void *ctx, longlong value, uint is_unsigned) {
291   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
292   DBUG_TRACE;
293   uint row = pctx->num_rows;
294   uint col = pctx->current_col;
295   pctx->current_col++;
296 
297   size_t len = snprintf(pctx->sql_str_value[row][col],
298                         sizeof(pctx->sql_str_value[row][col]),
299                         is_unsigned ? "%llu" : "%lld", value);
300 
301   pctx->sql_str_len[row][col] = len;
302   pctx->sql_longlong_value[row][col] = value;
303   pctx->sql_is_unsigned[row][col] = is_unsigned;
304 
305   return false;
306 }
307 
sql_get_decimal(void * ctx,const decimal_t * value)308 static int sql_get_decimal(void *ctx, const decimal_t *value) {
309   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
310   DBUG_TRACE;
311   uint row = pctx->num_rows;
312   uint col = pctx->current_col;
313   pctx->current_col++;
314 
315   size_t len = snprintf(pctx->sql_str_value[row][col],
316                         sizeof(pctx->sql_str_value[row][col]),
317                         "%s%d.%d(%d)[%s]", value->sign ? "+" : "-", value->intg,
318                         value->frac, value->len, (char *)value->buf);
319   pctx->sql_str_len[row][col] = len;
320   pctx->sql_decimal_value[row][col].intg = value->intg;
321   pctx->sql_decimal_value[row][col].frac = value->frac;
322   pctx->sql_decimal_value[row][col].len = value->len;
323   pctx->sql_decimal_value[row][col].sign = value->sign;
324   memset((void *)pctx->sql_decimal_value[row][col].buf, '\0', (int)value->len);
325   memcpy((void *)pctx->sql_decimal_value[row][col].buf, (void *)value->buf,
326          (int)value->len);
327 
328   return false;
329 }
330 
sql_get_double(void * ctx,double value,uint32 decimals)331 static int sql_get_double(void *ctx, double value, uint32 decimals) {
332   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
333   DBUG_TRACE;
334   uint row = pctx->num_rows;
335   uint col = pctx->current_col;
336   pctx->current_col++;
337 
338   size_t len = snprintf(pctx->sql_str_value[row][col],
339                         sizeof(pctx->sql_str_value[row][col]), "%3.7g", value);
340 
341   pctx->sql_str_len[row][col] = len;
342 
343   pctx->sql_double_value[row][col] = value;
344   pctx->sql_double_decimals[row][col] = decimals;
345 
346   return false;
347 }
348 
sql_get_date(void * ctx,const MYSQL_TIME * value)349 static int sql_get_date(void *ctx, const MYSQL_TIME *value) {
350   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
351   DBUG_TRACE;
352   uint row = pctx->num_rows;
353   uint col = pctx->current_col;
354   pctx->current_col++;
355 
356   size_t len =
357       snprintf(pctx->sql_str_value[row][col],
358                sizeof(pctx->sql_str_value[row][col]), "%s%4d-%02d-%02d",
359                value->neg ? "-" : "", value->year, value->month, value->day);
360   pctx->sql_str_len[row][col] = len;
361 
362   pctx->sql_date_value[row][col].year = value->year;
363   pctx->sql_date_value[row][col].month = value->month;
364   pctx->sql_date_value[row][col].day = value->day;
365 
366   pctx->sql_date_value[row][col].hour = value->hour;
367   pctx->sql_date_value[row][col].minute = value->minute;
368   pctx->sql_date_value[row][col].second = value->second;
369   pctx->sql_date_value[row][col].second_part = value->second_part;
370   pctx->sql_date_value[row][col].neg = value->neg;
371 
372   return false;
373 }
374 
sql_get_time(void * ctx,const MYSQL_TIME * value,uint decimals)375 static int sql_get_time(void *ctx, const MYSQL_TIME *value, uint decimals) {
376   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
377   DBUG_TRACE;
378   uint row = pctx->num_rows;
379   uint col = pctx->current_col;
380   pctx->current_col++;
381 
382   size_t len = snprintf(
383       pctx->sql_str_value[row][col], sizeof(pctx->sql_str_value[row][col]),
384       "%s%02d:%02d:%02d", value->neg ? "-" : "",
385       value->day ? (value->day * 24 + value->hour) : value->hour, value->minute,
386       value->second);
387 
388   pctx->sql_str_len[row][col] = len;
389 
390   pctx->sql_time_value[row][col].year = value->year;
391   pctx->sql_time_value[row][col].month = value->month;
392   pctx->sql_time_value[row][col].day = value->day;
393 
394   pctx->sql_time_value[row][col].hour = value->hour;
395   pctx->sql_time_value[row][col].minute = value->minute;
396   pctx->sql_time_value[row][col].second = value->second;
397   pctx->sql_time_value[row][col].second_part = value->second_part;
398   pctx->sql_time_value[row][col].neg = value->neg;
399   pctx->sql_time_decimals[row][col] = decimals;
400 
401   return false;
402 }
403 
sql_get_datetime(void * ctx,const MYSQL_TIME * value,uint decimals)404 static int sql_get_datetime(void *ctx, const MYSQL_TIME *value, uint decimals) {
405   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
406   DBUG_TRACE;
407   uint row = pctx->num_rows;
408   uint col = pctx->current_col;
409   pctx->current_col++;
410 
411   size_t len = snprintf(
412       pctx->sql_str_value[row][col], sizeof(pctx->sql_str_value[row][col]),
413       "%s%4d-%02d-%02d %02d:%02d:%02d", value->neg ? "-" : "", value->year,
414       value->month, value->day, value->hour, value->minute, value->second);
415 
416   pctx->sql_str_len[row][col] = len;
417 
418   pctx->sql_datetime_value[row][col].year = value->year;
419   pctx->sql_datetime_value[row][col].month = value->month;
420   pctx->sql_datetime_value[row][col].day = value->day;
421 
422   pctx->sql_datetime_value[row][col].hour = value->hour;
423   pctx->sql_datetime_value[row][col].minute = value->minute;
424   pctx->sql_datetime_value[row][col].second = value->second;
425   pctx->sql_datetime_value[row][col].second_part = value->second_part;
426   pctx->sql_datetime_value[row][col].neg = value->neg;
427   pctx->sql_datetime_decimals[row][col] = decimals;
428 
429   return false;
430 }
431 
sql_get_string(void * ctx,const char * const value,size_t length,const CHARSET_INFO * const)432 static int sql_get_string(void *ctx, const char *const value, size_t length,
433                           const CHARSET_INFO *const) {
434   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
435   DBUG_TRACE;
436   uint row = pctx->num_rows;
437   uint col = pctx->current_col;
438   pctx->current_col++;
439 
440   strncpy(pctx->sql_str_value[row][col], value, length);
441   pctx->sql_str_len[row][col] = length;
442 
443   return false;
444 }
445 
sql_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)446 static void sql_handle_ok(void *ctx, uint server_status,
447                           uint statement_warn_count, ulonglong affected_rows,
448                           ulonglong last_insert_id, const char *const message) {
449   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
450   DBUG_TRACE;
451   /* This could be an EOF */
452   if (!pctx->num_cols) pctx->num_rows = 0;
453   pctx->server_status = server_status;
454   pctx->warn_count = statement_warn_count;
455   pctx->affected_rows = affected_rows;
456   pctx->last_insert_id = last_insert_id;
457   if (message) strncpy(pctx->message, message, sizeof(pctx->message) - 1);
458   pctx->message[sizeof(pctx->message) - 1] = '\0';
459 }
460 
sql_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)461 static void sql_handle_error(void *ctx, uint sql_errno,
462                              const char *const err_msg,
463                              const char *const sqlstate) {
464   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
465   DBUG_TRACE;
466   pctx->sql_errno = sql_errno;
467   if (pctx->sql_errno) {
468     strcpy(pctx->err_msg, err_msg);
469     strcpy(pctx->sqlstate, sqlstate);
470   }
471   pctx->num_rows = 0;
472 }
473 
sql_shutdown(void *,int)474 static void sql_shutdown(void *, int) { DBUG_TRACE; }
475 
476 const struct st_command_service_cbs sql_cbs = {
477     sql_start_result_metadata,
478     sql_field_metadata,
479     sql_end_result_metadata,
480     sql_start_row,
481     sql_end_row,
482     sql_abort_row,
483     sql_get_client_capabilities,
484     sql_get_null,
485     sql_get_integer,
486     sql_get_longlong,
487     sql_get_decimal,
488     sql_get_double,
489     sql_get_date,
490     sql_get_time,
491     sql_get_datetime,
492     sql_get_string,
493     sql_handle_ok,
494     sql_handle_error,
495     sql_shutdown,
496 };
497 
get_data_str(void * ctx)498 static void get_data_str(void *ctx) {
499   char buffer[STRING_BUFFER_SIZE];
500   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
501 
502   /* get values */
503   if ((pctx->num_rows > 0) && (pctx->num_cols > 0)) {
504     for (uint col_count = 0; col_count < pctx->num_cols; col_count++) {
505       WRITE_VAL("%s  ", pctx->sql_field[col_count].col_name);
506     }
507     WRITE_STR("\n");
508 
509     for (uint row_count = 0; row_count < pctx->num_rows; row_count++) {
510       for (uint col_count = 0; col_count < pctx->num_cols; col_count++) {
511         WRITE_VAL("%s  ", pctx->sql_str_value[row_count][col_count]);
512       }
513       WRITE_STR("\n");
514     }
515     WRITE_STR("\n");
516 
517     /* Metadata */
518     WRITE_VAL("num_cols      : %d\n", pctx->num_cols);
519     WRITE_VAL("nb rows       : %d\n", pctx->num_rows);
520   }
521 }
522 
handle_error(void * ctx)523 static void handle_error(void *ctx) {
524   char buffer[STRING_BUFFER_SIZE];
525   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
526   /* handle_ok/error */
527   WRITE_VAL("error     : %d\n", pctx->sql_errno);
528   WRITE_VAL("error msg : %s\n", pctx->err_msg);
529 }
530 
531 #define EXEC_TEST_CMD(s, q, p, ctx) \
532   exec_test_cmd((s), (q), (p), (ctx), false, __FUNCTION__, __LINE__)
533 #define EXEC_TEST_CMD_EX(s, q, p, ctx, err) \
534   exec_test_cmd((s), (q), (p), (ctx), (err), __FUNCTION__, __LINE__)
535 
exec_test_cmd(MYSQL_SESSION session,const char * query,void * p MY_ATTRIBUTE ((unused)),void * ctx,bool expect_error,const char * func,uint line)536 static void exec_test_cmd(MYSQL_SESSION session, const char *query,
537                           void *p MY_ATTRIBUTE((unused)), void *ctx,
538                           bool expect_error, const char *func, uint line) {
539   char buffer[STRING_BUFFER_SIZE];
540   struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
541   pctx->reset();
542   cmd.com_query.query = query;
543   cmd.com_query.length = strlen(cmd.com_query.query);
544   WRITE_VAL("%s\n", query);
545   int fail = command_service_run_command(session, COM_QUERY, &cmd,
546                                          &my_charset_utf8_general_ci, &sql_cbs,
547                                          CS_TEXT_REPRESENTATION, ctx);
548   if (fail) {
549     srv_session_close(session);
550     if (!expect_error)
551       LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
552                    "test_session_info - ret code : %d at %s:%u", fail, func,
553                    line);
554   } else if (pctx->sql_errno)
555     handle_error(ctx);
556   else if (expect_error)
557     LogPluginErrMsg(
558         ERROR_LEVEL, ER_LOG_PRINTF_MSG,
559         "test_session_info - expected error but command did not fail at %s:%u",
560         func, line);
561   else {
562     if (pctx->num_cols) get_data_str(ctx);
563     WRITE_VAL("affected rows : %d\n", pctx->affected_rows);
564     WRITE_VAL("server status : %d\n", pctx->server_status);
565     WRITE_VAL("warn count    : %d\n", pctx->warn_count);
566   }
567   WRITE_STR("\n");
568 }
569 
test_com_init_db(void * p MY_ATTRIBUTE ((unused)),MYSQL_SESSION st_session,const char * db_name)570 static void test_com_init_db(void *p MY_ATTRIBUTE((unused)),
571                              MYSQL_SESSION st_session, const char *db_name) {
572   char buffer[STRING_BUFFER_SIZE];
573   DBUG_TRACE;
574 
575   struct st_plugin_ctx *plugin_ctx = new st_plugin_ctx();
576 
577   COM_DATA cmd;
578 
579   LEX_CSTRING lex_db_name = srv_session_info_get_current_db(st_session);
580   WRITE_VAL("current_db before init_db : %s\n", lex_db_name.str);
581 
582   cmd.com_init_db.db_name = db_name;
583   cmd.com_init_db.length = strlen(db_name);
584 
585   int fail = command_service_run_command(st_session, COM_INIT_DB, &cmd,
586                                          &my_charset_utf8_general_ci, &sql_cbs,
587                                          CS_TEXT_REPRESENTATION, plugin_ctx);
588 
589   if (fail) {
590     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "run_statement code: %d\n",
591                  fail);
592     delete plugin_ctx;
593     return;
594   }
595 
596   lex_db_name = srv_session_info_get_current_db(st_session);
597   WRITE_VAL("current_db after init_db  : %s\n", lex_db_name.str);
598 
599   delete plugin_ctx;
600 }
601 
test_sql(void * p)602 static void test_sql(void *p) {
603   char buffer[STRING_BUFFER_SIZE + 1];
604   char buffer_query[STRING_BUFFER_SIZE];
605 
606   DBUG_TRACE;
607   MYSQL_SESSION session_1, session_2, session_3;
608   struct st_plugin_ctx *plugin_ctx = new st_plugin_ctx();
609 
610   /* Opening session 1 */
611   WRITE_STR("Opening Session 1\n");
612   session_1 = srv_session_open(NULL, plugin_ctx);
613   if (!session_1)
614     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Opening Session 1 failed");
615   else
616     switch_user(session_1, user_privileged);
617 
618   /* Opening session 2 */
619   WRITE_STR("Opening Session 2\n");
620   session_2 = srv_session_open(NULL, plugin_ctx);
621   if (!session_2)
622     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Opening Session 2 failed");
623   else
624     switch_user(session_2, user_privileged);
625 
626   /* srv_session_info_get_thd and srv_session_info_get_session_id*/
627   /* Session 1 */
628   WRITE_SEP();
629   WRITE_STR(
630       "Session 1 : srv_session_info_get_thd and "
631       "srv_session_info_get_session_id\n");
632   WRITE_SEP();
633   my_thread_id session_1_id = srv_session_info_get_session_id(session_1);
634   my_thread_id session_2_id = srv_session_info_get_session_id(session_2);
635   MYSQL_THD thd = srv_session_info_get_thd(session_1);
636   unsigned long thd_id = thd_get_thread_id(thd);
637   if (thd_id != session_1_id) {
638     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
639                  "Thread handler id is NOT equal to session id "
640                  "srv_session_info_get_session_id(session_1)");
641     return;
642   } else {
643     WRITE_STR(
644         "Thread handler id IS equal to session id returned by "
645         "srv_session_info_get_session_id(Session_1)\n\n");
646   }
647 
648   /* Session 2 */
649   WRITE_SEP();
650   WRITE_STR(
651       "Session 2 : srv_session_info_get_thd and "
652       "srv_session_info_get_session_id\n");
653   WRITE_SEP();
654   thd = srv_session_info_get_thd(session_2);
655   thd_id = thd_get_thread_id(thd);
656 
657   if (thd_id != session_2_id) {
658     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
659                  "Thread handler id is NOT equal to session id "
660                  "srv_session_info_get_session_id(session_2)");
661     delete plugin_ctx;
662     return;
663   } else {
664     WRITE_STR(
665         "Thread handler id IS equal to session id returned by "
666         "srv_session_info_get_session_id(Session_2)\n\n");
667   }
668 
669   /* All information from performance_schema  */
670   snprintf(buffer_query, sizeof(buffer_query),
671            "SELECT "
672            "name,type,processlist_id,processlist_user,processlist_host,"
673            "processlist_db,processlist_command,processlist_state,processlist_"
674            "info,`role`,instrumented,history,connection_type FROM "
675            "performance_schema.threads WHERE processlist_id =  %u",
676            session_1_id);
677   EXEC_TEST_CMD(session_1, buffer_query, p, plugin_ctx);
678 
679   snprintf(buffer_query, sizeof(buffer_query),
680            "SELECT "
681            "name,type,processlist_id,processlist_user,processlist_host,"
682            "processlist_db,processlist_command,processlist_state,processlist_"
683            "info,`role`,instrumented,history,connection_type FROM "
684            "performance_schema.threads WHERE processlist_id =  %u",
685            session_2_id);
686   EXEC_TEST_CMD(session_2, buffer_query, p, plugin_ctx);
687 
688   /* srv_session_info_get_current_db */
689   /* Session 1 */
690   WRITE_SEP();
691   WRITE_STR("Session 1 : srv_session_info_get_current_db\n");
692   WRITE_SEP();
693   EXEC_TEST_CMD(session_1, "/*Session_1*/ SHOW TABLES LIKE '%slave%'", p,
694                 plugin_ctx);
695   test_com_init_db(p, session_1, "mysql");
696   WRITE_STR("\n");
697   EXEC_TEST_CMD(session_1, "/*Session_1*/ SHOW TABLES LIKE '%slave%'", p,
698                 plugin_ctx);
699 
700   EXEC_TEST_CMD(session_1, "/*Session_1*/ USE information_schema", p,
701                 plugin_ctx);
702   LEX_CSTRING db_name = srv_session_info_get_current_db(session_1);
703   WRITE_VAL("current_db after 'USE db_name' command : %s\n\n", db_name.str);
704 
705   test_com_init_db(p, session_1, "test");
706   WRITE_STR("\n");
707   EXEC_TEST_CMD(session_1, "/*Session_1*/ SHOW TABLES", p, plugin_ctx);
708   /* Session 2 */
709   WRITE_SEP();
710   WRITE_STR("Session 2 : srv_session_info_get_current_db\n");
711   WRITE_SEP();
712   EXEC_TEST_CMD(session_2, "/*Session_2*/ SHOW TABLES LIKE '%slave%'", p,
713                 plugin_ctx);
714   test_com_init_db(p, session_2, "mysql");
715   WRITE_STR("\n");
716   WRITE_STR("Session 2's view\n");
717   EXEC_TEST_CMD(session_2, "/*Session_2*/ SHOW TABLES LIKE '%slave%'", p,
718                 plugin_ctx);
719 
720   WRITE_STR("Session 2's view\n");
721   EXEC_TEST_CMD(session_2, "/*Session_2*/ USE information_schema", p,
722                 plugin_ctx);
723   db_name = srv_session_info_get_current_db(session_2);
724   WRITE_VAL("current_db after 'USE db_name' command : %s\n\n", db_name.str);
725 
726   test_com_init_db(p, session_2, "test");
727   WRITE_STR("\n");
728   WRITE_STR("Session 2's view\n");
729   EXEC_TEST_CMD(session_2, "/*Session_2*/ SHOW TABLES", p, plugin_ctx);
730 
731   /* srv_session_info_set/get_client_port */
732   /* Session 1 */
733   WRITE_SEP();
734   WRITE_STR("Session 1 : srv_session_info_set/get_client_port\n");
735   WRITE_SEP();
736   WRITE_VAL("Port before srv_session_info_set_client_port : %d\n",
737             srv_session_info_get_client_port(session_1));
738   srv_session_info_set_client_port(session_1, 100);
739   WRITE_VAL("Port after srv_session_info_set_client_port  : %d\n\n",
740             srv_session_info_get_client_port(session_1));
741 
742   WRITE_STR("Session 1's view\n");
743   EXEC_TEST_CMD(session_1,
744                 "/*Session_1*/ SELECT host FROM INFORMATION_SCHEMA.PROCESSLIST "
745                 "WHERE info LIKE 'PLUGIN%' ORDER BY id",
746                 p, plugin_ctx);
747   WRITE_STR("Session 2's view\n");
748   EXEC_TEST_CMD(session_2,
749                 "/*Session_2*/ SELECT host FROM INFORMATION_SCHEMA.PROCESSLIST "
750                 "WHERE info LIKE 'PLUGIN%' ORDER BY id",
751                 p, plugin_ctx);
752 
753   /* Session 2 */
754   WRITE_SEP();
755   WRITE_STR("Session 2 : srv_session_info_set/get_client_port\n");
756   WRITE_SEP();
757   WRITE_VAL("Port before srv_session_info_set_client_port : %d\n",
758             srv_session_info_get_client_port(session_2));
759   srv_session_info_set_client_port(session_2, 200);
760   WRITE_VAL("Port after srv_session_info_set_client_port  : %d\n\n",
761             srv_session_info_get_client_port(session_2));
762 
763   WRITE_STR("Session 1's view\n");
764   EXEC_TEST_CMD(session_1,
765                 "/*Session_1*/ SELECT host FROM INFORMATION_SCHEMA.PROCESSLIST "
766                 "WHERE info LIKE 'PLUGIN%' ORDER BY id",
767                 p, plugin_ctx);
768   WRITE_STR("Session 2's view\n");
769   EXEC_TEST_CMD(session_2,
770                 "/*Session_2*/ SELECT host FROM INFORMATION_SCHEMA.PROCESSLIST "
771                 "WHERE info LIKE 'PLUGIN%' ORDER BY id",
772                 p, plugin_ctx);
773 
774   /* srv_session_info_set_connection_type */
775   /* Session 1 */
776   WRITE_SEP();
777   WRITE_STR("Session 1 : srv_session_info_set_connection_type\n");
778   WRITE_SEP();
779   snprintf(buffer_query, sizeof(buffer_query),
780            "SELECT CONNECTION_TYPE, CONNECTION_TYPE IS NULL FROM "
781            "performance_schema.threads WHERE PROCESSLIST_ID =  %u "
782            "/*session_1_id*/",
783            session_1_id);
784   WRITE_STR("Session 1's view\n");
785   EXEC_TEST_CMD(session_1, buffer_query, p, plugin_ctx);
786 
787   WRITE_STR("Setting NO_VIO_TYPE on session_1\n");
788   if (0 == srv_session_info_set_connection_type(session_1, NO_VIO_TYPE))
789     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
790                  "srv_session_info_set_connection_type(NO_VIO_TYPE) "
791                  "should fail but did not");
792 
793   snprintf(buffer_query, sizeof(buffer_query),
794            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
795            "PROCESSLIST_ID =  %u /*session_1_id*/",
796            session_1_id);
797   WRITE_STR("Session 1's view\n");
798   EXEC_TEST_CMD(session_1, buffer_query, p, plugin_ctx);
799 
800   WRITE_STR("Setting VIO_TYPE_TCPIP on session_1\n");
801   srv_session_info_set_connection_type(session_1, VIO_TYPE_TCPIP);
802   snprintf(buffer_query, sizeof(buffer_query),
803            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
804            "PROCESSLIST_ID =  %u /*session_1_id*/",
805            session_1_id);
806   WRITE_STR("Session 1's view\n");
807   EXEC_TEST_CMD(session_1, buffer_query, p, plugin_ctx);
808 
809   WRITE_STR("Setting VIO_TYPE_NAMEDPIPE on session_1\n");
810   srv_session_info_set_connection_type(session_1, VIO_TYPE_NAMEDPIPE);
811   snprintf(buffer_query, sizeof(buffer_query),
812            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
813            "PROCESSLIST_ID =  %u /*session_1_id*/",
814            session_1_id);
815   WRITE_STR("Session 1's view\n");
816   EXEC_TEST_CMD(session_1, buffer_query, p, plugin_ctx);
817 
818   /* Session 2 */
819   WRITE_SEP();
820   WRITE_STR("Session 2 : srv_session_info_set_connection_type\n");
821   WRITE_SEP();
822   snprintf(buffer_query, sizeof(buffer_query),
823            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
824            "PROCESSLIST_ID =  %u /*session_2_id*/",
825            session_2_id);
826   WRITE_STR("Session 2's view\n");
827   EXEC_TEST_CMD(session_2, buffer_query, p, plugin_ctx);
828 
829   /* Now test with SSL/TLS */
830   WRITE_STR("Setting VIO_TYPE_SSL on session_2\n");
831   srv_session_info_set_connection_type(session_2, VIO_TYPE_SSL);
832   /* Don't delete the following. We check if set of type on detached session
833    * will affect PFS. The thread should be SSL */
834   WRITE_STR("Setting VIO_TYPE_TCPIP on session_1\n");
835   srv_session_info_set_connection_type(session_1, VIO_TYPE_TCPIP);
836   snprintf(buffer_query, sizeof(buffer_query),
837            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
838            "PROCESSLIST_ID =  %u /*session_2_id*/",
839            session_2_id);
840   WRITE_STR("Session 2's view\n");
841   EXEC_TEST_CMD(session_2, buffer_query, p, plugin_ctx);
842 
843   srv_session_info_set_connection_type(session_2, VIO_TYPE_SHARED_MEMORY);
844   snprintf(buffer_query, sizeof(buffer_query),
845            "SELECT CONNECTION_TYPE FROM performance_schema.threads WHERE "
846            "PROCESSLIST_ID =  %u  /*session_2_id*/",
847            session_2_id);
848   WRITE_STR("Session 2's view\n");
849   EXEC_TEST_CMD(session_2, buffer_query, p, plugin_ctx);
850 
851   /* srv_session_info_killed */
852   /* Session 1 */
853   WRITE_SEP();
854   WRITE_STR("BEFORE kill of Session 1\n");
855   WRITE_SEP();
856   EXEC_TEST_CMD(session_1,
857                 "SELECT ID, USER, HOST, DB, COMMAND, INFO FROM "
858                 "INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE 'PLUGIN%' "
859                 "ORDER BY id",
860                 p, plugin_ctx);
861   WRITE_SEP();
862   WRITE_VAL("srv_session_info_killed(Session_1) : %d\n",
863             srv_session_info_killed(session_1));
864   WRITE_VAL("srv_session_info_killed(Session_2) : %d\n",
865             srv_session_info_killed(session_2));
866 
867   WRITE_SEP();
868   WRITE_STR("Killing Session 1\n");
869   snprintf(buffer_query, sizeof(buffer_query),
870            "KILL CONNECTION %u /*session_1_id*/", session_1_id);
871   EXEC_TEST_CMD(session_2, buffer_query, p, plugin_ctx);
872 
873   WRITE_SEP();
874   WRITE_STR("AFTER kill of Session 1\n");
875   WRITE_SEP();
876   EXEC_TEST_CMD_EX(session_1,
877                    "SELECT ID, USER, HOST, DB, COMMAND, INFO FROM "
878                    "INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE 'PLUGIN%' "
879                    "ORDER BY id",
880                    p, plugin_ctx, true);
881   session_1 = nullptr;  // session_1 is closed in EXEC_TEST_CMD_EX.
882   WRITE_SEP();
883   WRITE_VAL("srv_session_info_killed(Session 1) : %d\n",
884             srv_session_info_killed(session_1));
885   WRITE_VAL("srv_session_info_killed(Session 2) : %d\n",
886             srv_session_info_killed(session_2));
887 
888   /* Close session 1 */
889   WRITE_SEP();
890   WRITE_STR("Closing Session 1\n");
891   if (srv_session_close(session_1))
892     WRITE_STR(
893         "Closing Session 1 failed as expected. It was already closed by "
894         "EXEC_TEST_CMD\n");
895 
896   WRITE_SEP();
897   WRITE_STR("Get/Set session info with closed session(Session 1)\n");
898   WRITE_SEP();
899 
900   db_name = srv_session_info_get_current_db(session_1);
901 
902   WRITE_VAL("srv_session_info_get_thd             : %d\n",
903             (bool)srv_session_info_get_thd(session_1));
904   WRITE_VAL("srv_session_info_get_session_id      : %d\n",
905             srv_session_info_get_session_id(session_1));
906   WRITE_VAL("srv_session_info_set_client_port     : %d\n",
907             srv_session_info_set_client_port(session_1, 11111));
908   WRITE_VAL("srv_session_info_get_client_port     : %d\n",
909             srv_session_info_get_client_port(session_1));
910   WRITE_VAL("srv_session_info_get_current_db      : %s\n", db_name.str);
911   WRITE_VAL(
912       "srv_session_info_set_connection_type : %d\n",
913       srv_session_info_set_connection_type(session_1, VIO_TYPE_SHARED_MEMORY));
914   WRITE_STR("\n");
915 
916   WRITE_SEP();
917   EXEC_TEST_CMD_EX(session_1,
918                    "SELECT ID, USER, HOST, DB, COMMAND, INFO FROM "
919                    "INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE 'PLUGIN%' "
920                    "ORDER BY id",
921                    p, plugin_ctx, true);
922   WRITE_SEP();
923   WRITE_STR("Perform KILL QUERY and suicide (KILL CONNECTION) on Session 2\n");
924   WRITE_SEP();
925   snprintf(buffer_query, sizeof(buffer_query), "KILL QUERY %i /*session_2_id*/",
926            session_2_id);
927   WRITE_VAL("%s\n", buffer_query);
928   cmd.com_query.query = buffer_query;
929   cmd.com_query.length = strlen(buffer_query);
930 
931   int fail = command_service_run_command(session_2, COM_QUERY, &cmd,
932                                          &my_charset_utf8_general_ci, &sql_cbs,
933                                          CS_TEXT_REPRESENTATION, plugin_ctx);
934 
935   if (fail) {
936     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "run_statement code: %d\n",
937                  fail);
938     delete plugin_ctx;
939     return;
940   }
941 
942   WRITE_VAL("srv_session_info_killed(Session 2) : %d\n",
943             srv_session_info_killed(session_2));
944 
945   snprintf(buffer_query, sizeof(buffer_query),
946            "KILL CONNECTION %i  /*session_2_id*/", session_2_id);
947   WRITE_VAL("%s\n", buffer_query);
948   cmd.com_query.query = buffer_query;
949   cmd.com_query.length = strlen(buffer_query);
950 
951   fail = command_service_run_command(session_2, COM_QUERY, &cmd,
952                                      &my_charset_utf8_general_ci, &sql_cbs,
953                                      CS_TEXT_REPRESENTATION, plugin_ctx);
954 
955   if (fail) {
956     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "run_statement code: %d\n",
957                  fail);
958     delete plugin_ctx;
959     return;
960   }
961 
962   WRITE_VAL("srv_session_info_killed(Session 2) : %d\n",
963             srv_session_info_killed(session_2));
964 
965   db_name = srv_session_info_get_current_db(session_2);
966 
967   WRITE_SEP();
968   WRITE_STR("Get/Set session info with killed session(Session 2)\n");
969   WRITE_SEP();
970   WRITE_VAL("srv_session_info_get_thd             : %d\n",
971             (bool)srv_session_info_get_thd(session_2));
972   WRITE_VAL("srv_session_info_get_session_id      : %d\n",
973             srv_session_info_get_session_id(session_2));
974   WRITE_VAL("srv_session_info_set_client_port     : %d\n",
975             srv_session_info_set_client_port(session_2, 11111));
976   WRITE_VAL("srv_session_info_get_client_port     : %d\n",
977             srv_session_info_get_client_port(session_2));
978   WRITE_VAL("srv_session_info_get_current_db      : %s\n", db_name.str);
979   WRITE_VAL(
980       "srv_session_info_set_connection_type : %d\n",
981       srv_session_info_set_connection_type(session_2, VIO_TYPE_SHARED_MEMORY));
982   WRITE_STR("\n");
983 
984   session_3 = srv_session_open(NULL, plugin_ctx);
985   if (!session_3)
986     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Opening Session 3 failed");
987   else {
988     switch_user(session_3, user_privileged);
989 
990     WRITE_SEP();
991     WRITE_STR(
992         "Session 2 got killed but not closed, thus it will appear in the "
993         "processlist as Killed\n");
994     WRITE_SEP();
995     EXEC_TEST_CMD(session_3,
996                   "/*Session 3*/SELECT ID, USER, HOST, DB, COMMAND, INFO FROM "
997                   "INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE 'PLUGIN%' "
998                   "ORDER BY id",
999                   p, plugin_ctx);
1000 
1001     WRITE_STR("Closing Session 2\n");
1002     if (srv_session_close(session_2))
1003       LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Closing Session 2 failed");
1004 
1005     WRITE_STR("Closing Session 3\n");
1006     if (srv_session_close(session_3))
1007       LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Closing Session 3 failed");
1008   }
1009 
1010   delete plugin_ctx;
1011 }
1012 
1013 struct test_thread_context {
1014   my_thread_handle thread;
1015   void *p;
1016   bool thread_finished;
1017   void (*test_function)(void *);
1018 };
1019 
test_sql_threaded_wrapper(void * param)1020 static void *test_sql_threaded_wrapper(void *param) {
1021   char buffer[STRING_BUFFER_SIZE];
1022   struct test_thread_context *context = (struct test_thread_context *)param;
1023 
1024   WRITE_SEP();
1025   WRITE_STR("init thread\n");
1026   if (srv_session_init_thread(context->p))
1027     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
1028                  "srv_session_init_thread failed.");
1029 
1030   context->test_function(context->p);
1031 
1032   WRITE_STR("deinit thread\n");
1033   srv_session_deinit_thread();
1034 
1035   context->thread_finished = true;
1036   return nullptr;
1037 }
1038 
create_log_file(const char * log_name)1039 static void create_log_file(const char *log_name) {
1040   char filename[FN_REFLEN];
1041 
1042   fn_format(filename, log_name, "", ".log",
1043             MY_REPLACE_EXT | MY_UNPACK_FILENAME);
1044   unlink(filename);
1045   outfile = my_open(filename, O_CREAT | O_RDWR, MYF(0));
1046 }
1047 
1048 #ifdef HAVE_PSI_INTERFACE
1049 static PSI_thread_key key_thread_session_info = PSI_NOT_INSTRUMENTED;
1050 static PSI_thread_info session_info_threads[] = {
1051     {&key_thread_session_info, "session_info", 0, 0, PSI_DOCUMENT_ME}};
1052 #endif  // HAVE_PSI_INTERFACE
1053 
test_in_spawned_thread(void * p,void (* test_function)(void *))1054 static void test_in_spawned_thread(void *p, void (*test_function)(void *)) {
1055   my_thread_attr_t attr; /* Thread attributes */
1056   my_thread_attr_init(&attr);
1057   (void)my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
1058 
1059   struct test_thread_context context;
1060 
1061   context.p = p;
1062   context.thread_finished = false;
1063   context.test_function = test_function;
1064 
1065   /* now create the thread and call test_session within the thread. */
1066   if (mysql_thread_create(key_thread_session_info, &(context.thread), &attr,
1067                           test_sql_threaded_wrapper, &context) != 0)
1068     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
1069                  "Could not create test session thread");
1070   else
1071     my_thread_join(&context.thread, nullptr);
1072 }
1073 
test_sql_service_plugin_init(void * p)1074 static int test_sql_service_plugin_init(void *p) {
1075   char buffer[STRING_BUFFER_SIZE];
1076   DBUG_TRACE;
1077   if (init_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs)) return 1;
1078   LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Installation.");
1079 
1080   create_log_file(log_filename);
1081 
1082 #ifdef HAVE_PSI_INTERFACE
1083   const char *const category = "test_service_sql";
1084 
1085   mysql_thread_register(category, session_info_threads,
1086                         static_cast<int>(array_elements(session_info_threads)));
1087 #endif  // HAVE_PSI_INTERFACE
1088 
1089   WRITE_SEP();
1090   WRITE_STR("Test in a server thread\n");
1091   test_sql(p);
1092 
1093   /* Test in a new thread */
1094   WRITE_STR("Follows threaded run\n");
1095   test_in_spawned_thread(p, test_sql);
1096 
1097   my_close(outfile, MYF(0));
1098 
1099   return 0;
1100 }
1101 
test_sql_service_plugin_deinit(void * p MY_ATTRIBUTE ((unused)))1102 static int test_sql_service_plugin_deinit(void *p MY_ATTRIBUTE((unused))) {
1103   DBUG_TRACE;
1104   LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Uninstallation.");
1105   deinit_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs);
1106   return 0;
1107 }
1108 
1109 struct st_mysql_daemon test_sql_service_plugin = {
1110     MYSQL_DAEMON_INTERFACE_VERSION};
1111 
1112 /*
1113   Plugin library descriptor
1114 */
1115 
mysql_declare_plugin(test_daemon)1116 mysql_declare_plugin(test_daemon){
1117     MYSQL_DAEMON_PLUGIN,
1118     &test_sql_service_plugin,
1119     "test_session_info",
1120     PLUGIN_AUTHOR_ORACLE,
1121     "Test session information",
1122     PLUGIN_LICENSE_GPL,
1123     test_sql_service_plugin_init,   /* Plugin Init      */
1124     nullptr,                        /* Plugin Check uninstall */
1125     test_sql_service_plugin_deinit, /* Plugin Deinit    */
1126     0x0100,                         /* 1.0              */
1127     nullptr,                        /* status variables */
1128     nullptr,                        /* system variables */
1129     nullptr,                        /* config options   */
1130     0,                              /* flags            */
1131 } mysql_declare_plugin_end;
1132