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 #include <fcntl.h>
24 #include <mysql/plugin.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27
28 #include "m_string.h"
29 #include "my_dbug.h"
30 #include "my_inttypes.h"
31 #include "my_io.h"
32 #include "my_sys.h" // my_write, my_malloc
33 #include "mysql_com.h"
34 #include "template_utils.h"
35
36 #define LOG_COMPONENT_TAG "test_session_detach"
37
38 #include <mysql/components/my_service.h>
39 #include <mysql/components/services/log_builtins.h>
40 #include <mysqld_error.h>
41
42 static const char *log_filename = "test_session_detach";
43
44 #define STRING_BUFFER_SIZE 1100
45
46 static const char *sep =
47 "========================================================================="
48 "\n";
49
50 #define WRITE_SEP() \
51 my_write(outfile, pointer_cast<const uchar *>(sep), strlen(sep), MYF(0))
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 SERVICE_TYPE(registry) *reg_srv = nullptr;
72 SERVICE_TYPE(log_builtins) *log_bi = nullptr;
73 SERVICE_TYPE(log_builtins_string) *log_bs = nullptr;
74
75 static File outfile;
76
77 struct st_send_field_n {
78 char db_name[256];
79 char table_name[256];
80 char org_table_name[256];
81 char col_name[256];
82 char org_col_name[256];
83 unsigned long length;
84 unsigned int charsetnr;
85 unsigned int flags;
86 unsigned int decimals;
87 enum_field_types type;
88 };
89
90 struct st_decimal_n {
91 int intg, frac, len;
92 bool sign;
93 decimal_digit_t buf[256];
94 };
95
96 struct st_plugin_ctx {
97 const CHARSET_INFO *resultcs;
98 uint meta_server_status;
99 uint meta_warn_count;
100 uint current_col;
101 uint num_cols;
102 uint num_rows;
103 st_send_field_n sql_field[64];
104 char sql_str_value[64][64][256];
105 size_t sql_str_len[64][64];
106 int sql_int_value[64][64];
107 // longlong sql_int_value[64][64];
108 longlong sql_longlong_value[64][64];
109 uint sql_is_unsigned[64][64];
110 st_decimal_n sql_decimal_value[64][64];
111 double sql_double_value[64][64];
112 uint32 sql_double_decimals[64][64];
113 MYSQL_TIME sql_date_value[64][64];
114 MYSQL_TIME sql_time_value[64][64];
115 uint sql_time_decimals[64][64];
116 MYSQL_TIME sql_datetime_value[64][64];
117 uint sql_datetime_decimals[64][64];
118
119 uint server_status;
120 uint warn_count;
121 uint affected_rows;
122 uint last_insert_id;
123 char message[1024];
124
125 uint sql_errno;
126 char err_msg[1024];
127 char sqlstate[6];
st_plugin_ctxst_plugin_ctx128 st_plugin_ctx() { reset(); }
129
resetst_plugin_ctx130 void reset() {
131 resultcs = nullptr;
132 server_status = 0;
133 current_col = 0;
134 warn_count = 0;
135 num_cols = 0;
136 num_rows = 0;
137 memset(&sql_field, 0, 64 * sizeof(st_send_field_n));
138 memset(&sql_str_value, 0, 64 * 64 * 256 * sizeof(char));
139 memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
140 memset(&sql_int_value, 0, 64 * 64 * sizeof(longlong));
141 memset(&sql_longlong_value, 0, 64 * 64 * sizeof(longlong));
142 memset(&sql_is_unsigned, 0, 64 * 64 * sizeof(uint));
143 memset(&sql_decimal_value, 0, 64 * 64 * sizeof(st_decimal_n));
144 memset(&sql_double_value, 0, 64 * 64 * sizeof(double));
145 memset(&sql_double_decimals, 0, 64 * 64 * sizeof(uint32));
146 memset(&sql_date_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
147 memset(&sql_time_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
148 memset(&sql_time_decimals, 0, 64 * 64 * sizeof(uint));
149 memset(&sql_datetime_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
150 memset(&sql_datetime_decimals, 0, 64 * 64 * sizeof(uint));
151
152 server_status = 0;
153 warn_count = 0;
154 affected_rows = 0;
155 last_insert_id = 0;
156 memset(&message, 0, sizeof(message));
157
158 sql_errno = 0;
159 memset(&err_msg, 0, sizeof(err_msg));
160 memset(&sqlstate, 0, sizeof(sqlstate));
161 }
162 };
163
sql_start_result_metadata(void * ctx,uint num_cols,uint,const CHARSET_INFO * resultcs)164 static int sql_start_result_metadata(void *ctx, uint num_cols, uint,
165 const CHARSET_INFO *resultcs) {
166 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
167 DBUG_TRACE;
168 DBUG_PRINT("info", ("resultcs->number: %d", resultcs->number));
169 DBUG_PRINT("info", ("resultcs->csname: %s", resultcs->csname));
170 DBUG_PRINT("info", ("resultcs->name: %s", resultcs->name));
171 pctx->num_cols = num_cols;
172 pctx->resultcs = resultcs;
173 pctx->current_col = 0;
174 return false;
175 }
176
sql_field_metadata(void * ctx,struct st_send_field * field,const CHARSET_INFO *)177 static int sql_field_metadata(void *ctx, struct st_send_field *field,
178 const CHARSET_INFO *) {
179 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
180 st_send_field_n *cfield = &pctx->sql_field[pctx->current_col];
181 DBUG_TRACE;
182 DBUG_PRINT("info", ("field->db_name: %s", field->db_name));
183 DBUG_PRINT("info", ("field->table_name: %s", field->table_name));
184 DBUG_PRINT("info", ("field->org_table_name: %s", field->org_table_name));
185 DBUG_PRINT("info", ("field->col_name: %s", field->col_name));
186 DBUG_PRINT("info", ("field->org_col_name: %s", field->org_col_name));
187 DBUG_PRINT("info", ("field->length: %d", (int)field->length));
188 DBUG_PRINT("info", ("field->charsetnr: %d", (int)field->charsetnr));
189 DBUG_PRINT("info", ("field->flags: %d", (int)field->flags));
190 DBUG_PRINT("info", ("field->decimals: %d", (int)field->decimals));
191 DBUG_PRINT("info", ("field->type: %d", (int)field->type));
192
193 strcpy(cfield->db_name, field->db_name);
194 strcpy(cfield->table_name, field->table_name);
195 strcpy(cfield->org_table_name, field->org_table_name);
196 strcpy(cfield->col_name, field->col_name);
197 strcpy(cfield->org_col_name, field->org_col_name);
198 cfield->length = field->length;
199 cfield->charsetnr = field->charsetnr;
200 cfield->flags = field->flags;
201 cfield->decimals = field->decimals;
202 cfield->type = field->type;
203
204 pctx->current_col++;
205 return false;
206 }
207
sql_end_result_metadata(void * ctx,uint server_status,uint warn_count)208 static int sql_end_result_metadata(void *ctx, uint server_status,
209 uint warn_count) {
210 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
211 DBUG_TRACE;
212 pctx->meta_server_status = server_status;
213 pctx->meta_warn_count = warn_count;
214 pctx->num_rows = 0;
215 return false;
216 }
217
sql_start_row(void * ctx)218 static int sql_start_row(void *ctx) {
219 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
220 DBUG_TRACE;
221 pctx->current_col = 0;
222 return false;
223 }
224
sql_end_row(void * ctx)225 static int sql_end_row(void *ctx) {
226 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
227 DBUG_TRACE;
228 pctx->num_rows++;
229 return false;
230 }
231
sql_abort_row(void * ctx)232 static void sql_abort_row(void *ctx) {
233 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
234 DBUG_TRACE;
235 pctx->current_col = 0;
236 }
237
sql_get_client_capabilities(void *)238 static ulong sql_get_client_capabilities(void *) {
239 DBUG_TRACE;
240 return 0;
241 }
242
sql_get_null(void * ctx)243 static int sql_get_null(void *ctx) {
244 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
245 DBUG_TRACE;
246 uint row = pctx->num_rows;
247 uint col = pctx->current_col;
248 pctx->current_col++;
249
250 memcpy(pctx->sql_str_value[row][col], "[NULL]", sizeof("[NULL]"));
251 pctx->sql_str_len[row][col] = sizeof("[NULL]") - 1;
252
253 return false;
254 }
255
sql_get_integer(void * ctx,longlong value)256 static int sql_get_integer(void *ctx, longlong value) {
257 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
258 DBUG_TRACE;
259 uint row = pctx->num_rows;
260 uint col = pctx->current_col;
261 pctx->current_col++;
262
263 size_t len = snprintf(pctx->sql_str_value[row][col],
264 sizeof(pctx->sql_str_value[row][col]), "%lld", value);
265 pctx->sql_str_len[row][col] = len;
266 pctx->sql_int_value[row][col] = value;
267
268 return false;
269 }
270
sql_get_longlong(void * ctx,longlong value,uint is_unsigned)271 static int sql_get_longlong(void *ctx, longlong value, uint is_unsigned) {
272 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
273 DBUG_TRACE;
274 uint row = pctx->num_rows;
275 uint col = pctx->current_col;
276 pctx->current_col++;
277
278 size_t len = snprintf(pctx->sql_str_value[row][col],
279 sizeof(pctx->sql_str_value[row][col]),
280 is_unsigned ? "%llu" : "%lld", value);
281
282 pctx->sql_str_len[row][col] = len;
283 pctx->sql_longlong_value[row][col] = value;
284 pctx->sql_is_unsigned[row][col] = is_unsigned;
285
286 return false;
287 }
288
sql_get_decimal(void * ctx,const decimal_t * value)289 static int sql_get_decimal(void *ctx, const decimal_t *value) {
290 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
291 DBUG_TRACE;
292 uint row = pctx->num_rows;
293 uint col = pctx->current_col;
294 pctx->current_col++;
295
296 size_t len = snprintf(pctx->sql_str_value[row][col],
297 sizeof(pctx->sql_str_value[row][col]),
298 "%s%d.%d(%d)[%s]", value->sign ? "+" : "-", value->intg,
299 value->frac, value->len, (char *)value->buf);
300 pctx->sql_str_len[row][col] = len;
301 pctx->sql_decimal_value[row][col].intg = value->intg;
302 pctx->sql_decimal_value[row][col].frac = value->frac;
303 pctx->sql_decimal_value[row][col].len = value->len;
304 pctx->sql_decimal_value[row][col].sign = value->sign;
305 memset((void *)pctx->sql_decimal_value[row][col].buf, '\0', (int)value->len);
306 memcpy((void *)pctx->sql_decimal_value[row][col].buf, (void *)value->buf,
307 (int)value->len);
308
309 return false;
310 }
311
sql_get_double(void * ctx,double value,uint32 decimals)312 static int sql_get_double(void *ctx, double value, uint32 decimals) {
313 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
314 DBUG_TRACE;
315 uint row = pctx->num_rows;
316 uint col = pctx->current_col;
317 pctx->current_col++;
318
319 size_t len = snprintf(pctx->sql_str_value[row][col],
320 sizeof(pctx->sql_str_value[row][col]), "%3.7g", value);
321
322 pctx->sql_str_len[row][col] = len;
323
324 pctx->sql_double_value[row][col] = value;
325 pctx->sql_double_decimals[row][col] = decimals;
326
327 return false;
328 }
329
sql_get_date(void * ctx,const MYSQL_TIME * value)330 static int sql_get_date(void *ctx, const MYSQL_TIME *value) {
331 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
332 DBUG_TRACE;
333 uint row = pctx->num_rows;
334 uint col = pctx->current_col;
335 pctx->current_col++;
336
337 size_t len =
338 snprintf(pctx->sql_str_value[row][col],
339 sizeof(pctx->sql_str_value[row][col]), "%s%4d-%02d-%02d",
340 value->neg ? "-" : "", value->year, value->month, value->day);
341 pctx->sql_str_len[row][col] = len;
342
343 pctx->sql_date_value[row][col].year = value->year;
344 pctx->sql_date_value[row][col].month = value->month;
345 pctx->sql_date_value[row][col].day = value->day;
346
347 pctx->sql_date_value[row][col].hour = value->hour;
348 pctx->sql_date_value[row][col].minute = value->minute;
349 pctx->sql_date_value[row][col].second = value->second;
350 pctx->sql_date_value[row][col].second_part = value->second_part;
351 pctx->sql_date_value[row][col].neg = value->neg;
352
353 return false;
354 }
355
sql_get_time(void * ctx,const MYSQL_TIME * value,uint decimals)356 static int sql_get_time(void *ctx, const MYSQL_TIME *value, uint decimals) {
357 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
358 DBUG_TRACE;
359 uint row = pctx->num_rows;
360 uint col = pctx->current_col;
361 pctx->current_col++;
362
363 size_t len = snprintf(
364 pctx->sql_str_value[row][col], sizeof(pctx->sql_str_value[row][col]),
365 "%s%02d:%02d:%02d", value->neg ? "-" : "",
366 value->day ? (value->day * 24 + value->hour) : value->hour, value->minute,
367 value->second);
368
369 pctx->sql_str_len[row][col] = len;
370
371 pctx->sql_time_value[row][col].year = value->year;
372 pctx->sql_time_value[row][col].month = value->month;
373 pctx->sql_time_value[row][col].day = value->day;
374
375 pctx->sql_time_value[row][col].hour = value->hour;
376 pctx->sql_time_value[row][col].minute = value->minute;
377 pctx->sql_time_value[row][col].second = value->second;
378 pctx->sql_time_value[row][col].second_part = value->second_part;
379 pctx->sql_time_value[row][col].neg = value->neg;
380 pctx->sql_time_decimals[row][col] = decimals;
381
382 return false;
383 }
384
sql_get_datetime(void * ctx,const MYSQL_TIME * value,uint decimals)385 static int sql_get_datetime(void *ctx, const MYSQL_TIME *value, uint decimals) {
386 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
387 DBUG_TRACE;
388 uint row = pctx->num_rows;
389 uint col = pctx->current_col;
390 pctx->current_col++;
391
392 size_t len = snprintf(
393 pctx->sql_str_value[row][col], sizeof(pctx->sql_str_value[row][col]),
394 "%s%4d-%02d-%02d %02d:%02d:%02d", value->neg ? "-" : "", value->year,
395 value->month, value->day, value->hour, value->minute, value->second);
396
397 pctx->sql_str_len[row][col] = len;
398
399 pctx->sql_datetime_value[row][col].year = value->year;
400 pctx->sql_datetime_value[row][col].month = value->month;
401 pctx->sql_datetime_value[row][col].day = value->day;
402
403 pctx->sql_datetime_value[row][col].hour = value->hour;
404 pctx->sql_datetime_value[row][col].minute = value->minute;
405 pctx->sql_datetime_value[row][col].second = value->second;
406 pctx->sql_datetime_value[row][col].second_part = value->second_part;
407 pctx->sql_datetime_value[row][col].neg = value->neg;
408 pctx->sql_datetime_decimals[row][col] = decimals;
409
410 return false;
411 }
412
sql_get_string(void * ctx,const char * const value,size_t length,const CHARSET_INFO * const)413 static int sql_get_string(void *ctx, const char *const value, size_t length,
414 const CHARSET_INFO *const) {
415 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
416 DBUG_TRACE;
417 uint row = pctx->num_rows;
418 uint col = pctx->current_col;
419 pctx->current_col++;
420
421 strncpy(pctx->sql_str_value[row][col], value, length);
422 pctx->sql_str_len[row][col] = length;
423
424 return false;
425 }
426
sql_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)427 static void sql_handle_ok(void *ctx, uint server_status,
428 uint statement_warn_count, ulonglong affected_rows,
429 ulonglong last_insert_id, const char *const message) {
430 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
431 DBUG_TRACE;
432 /* This could be an EOF */
433 if (!pctx->num_cols) pctx->num_rows = 0;
434 pctx->server_status = server_status;
435 pctx->warn_count = statement_warn_count;
436 pctx->affected_rows = affected_rows;
437 pctx->last_insert_id = last_insert_id;
438 if (message) strncpy(pctx->message, message, sizeof(pctx->message) - 1);
439 pctx->message[sizeof(pctx->message) - 1] = '\0';
440 }
441
sql_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)442 static void sql_handle_error(void *ctx, uint sql_errno,
443 const char *const err_msg,
444 const char *const sqlstate) {
445 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
446 DBUG_TRACE;
447 pctx->sql_errno = sql_errno;
448 if (pctx->sql_errno) {
449 strcpy(pctx->err_msg, err_msg);
450 strcpy(pctx->sqlstate, sqlstate);
451 }
452 pctx->num_rows = 0;
453 }
454
sql_shutdown(void *,int)455 static void sql_shutdown(void *, int) { DBUG_TRACE; }
456
457 const struct st_command_service_cbs sql_cbs = {
458 sql_start_result_metadata,
459 sql_field_metadata,
460 sql_end_result_metadata,
461 sql_start_row,
462 sql_end_row,
463 sql_abort_row,
464 sql_get_client_capabilities,
465 sql_get_null,
466 sql_get_integer,
467 sql_get_longlong,
468 sql_get_decimal,
469 sql_get_double,
470 sql_get_date,
471 sql_get_time,
472 sql_get_datetime,
473 sql_get_string,
474 sql_handle_ok,
475 sql_handle_error,
476 sql_shutdown,
477 };
478
fieldtype2str(enum enum_field_types type)479 static const char *fieldtype2str(enum enum_field_types type) {
480 switch (type) {
481 case MYSQL_TYPE_BIT:
482 return "BIT";
483 case MYSQL_TYPE_BLOB:
484 return "BLOB";
485 case MYSQL_TYPE_DATE:
486 return "DATE";
487 case MYSQL_TYPE_DATETIME:
488 return "DATETIME";
489 case MYSQL_TYPE_NEWDECIMAL:
490 return "NEWDECIMAL";
491 case MYSQL_TYPE_DECIMAL:
492 return "DECIMAL";
493 case MYSQL_TYPE_DOUBLE:
494 return "DOUBLE";
495 case MYSQL_TYPE_ENUM:
496 return "ENUM";
497 case MYSQL_TYPE_FLOAT:
498 return "FLOAT";
499 case MYSQL_TYPE_GEOMETRY:
500 return "GEOMETRY";
501 case MYSQL_TYPE_INT24:
502 return "INT24";
503 case MYSQL_TYPE_LONG:
504 return "LONG";
505 case MYSQL_TYPE_LONGLONG:
506 return "LONGLONG";
507 case MYSQL_TYPE_LONG_BLOB:
508 return "LONG_BLOB";
509 case MYSQL_TYPE_MEDIUM_BLOB:
510 return "MEDIUM_BLOB";
511 case MYSQL_TYPE_NEWDATE:
512 return "NEWDATE";
513 case MYSQL_TYPE_NULL:
514 return "NULL";
515 case MYSQL_TYPE_SET:
516 return "SET";
517 case MYSQL_TYPE_SHORT:
518 return "SHORT";
519 case MYSQL_TYPE_STRING:
520 return "STRING";
521 case MYSQL_TYPE_TIME:
522 return "TIME";
523 case MYSQL_TYPE_TIMESTAMP:
524 return "TIMESTAMP";
525 case MYSQL_TYPE_TINY:
526 return "TINY";
527 case MYSQL_TYPE_TINY_BLOB:
528 return "TINY_BLOB";
529 case MYSQL_TYPE_VARCHAR:
530 return "VARCHAR";
531 case MYSQL_TYPE_VAR_STRING:
532 return "VAR_STRING";
533 case MYSQL_TYPE_YEAR:
534 return "YEAR";
535 default:
536 return "?-unknown-?";
537 }
538 }
539
get_data_integer(void * ctx)540 static void get_data_integer(void *ctx) {
541 char buffer[STRING_BUFFER_SIZE];
542 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
543
544 /* start metadata */
545 WRITE_VAL("num_cols : %d\n", pctx->num_cols);
546 WRITE_VAL("nb rows : %d\n", pctx->num_rows);
547
548 /* get values */
549 for (uint col = 0; col < pctx->num_cols; col++) {
550 WRITE_VAL("%s ", pctx->sql_field[col].col_name);
551 WRITE_VAL2("%s(%u)\t", fieldtype2str(pctx->sql_field[col].type),
552 pctx->sql_field[col].type);
553 }
554 WRITE_STR("\n");
555 for (uint row = 0; row < pctx->num_rows; row++) {
556 for (uint col = 0; col < pctx->num_cols; col++) {
557 WRITE_VAL("%d\t\t", pctx->sql_int_value[row][col]);
558 }
559 WRITE_STR("\n");
560 }
561 WRITE_STR("\n");
562 }
563
handle_error(void * ctx)564 static void handle_error(void *ctx) {
565 char buffer[STRING_BUFFER_SIZE];
566 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
567
568 /* handle_ok/error */
569 if (pctx->sql_errno) {
570 WRITE_VAL("error : %d\n", pctx->sql_errno);
571 WRITE_VAL("error msg : %s\n", pctx->err_msg);
572 } else {
573 WRITE_VAL("affected rows : %d\n", pctx->affected_rows);
574 WRITE_VAL("server status : %d\n", pctx->server_status);
575 WRITE_VAL("warn count : %d\n", pctx->warn_count);
576 }
577 }
578
exec_test_cmd(MYSQL_SESSION session,const char * test_cmd,void * p MY_ATTRIBUTE ((unused)),void * ctx)579 static void exec_test_cmd(MYSQL_SESSION session, const char *test_cmd,
580 void *p MY_ATTRIBUTE((unused)), void *ctx) {
581 char buffer[STRING_BUFFER_SIZE];
582 COM_DATA cmd;
583 struct st_plugin_ctx *pctx = (struct st_plugin_ctx *)ctx;
584
585 WRITE_VAL("%s\n", test_cmd);
586 pctx->reset();
587 cmd.com_query.query = test_cmd;
588 cmd.com_query.length = strlen(cmd.com_query.query);
589 int fail = command_service_run_command(session, COM_QUERY, &cmd,
590 &my_charset_utf8_general_ci, &sql_cbs,
591 CS_BINARY_REPRESENTATION, ctx);
592
593 if (fail)
594 LogPluginErrMsg(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
595 "test_sql_2_sessions: ret code: %d", 0);
596 else {
597 if (pctx->num_cols) get_data_integer(ctx);
598 handle_error(ctx);
599 }
600 }
601
test_sql(void * p)602 static void test_sql(void *p) {
603 char buffer[STRING_BUFFER_SIZE];
604
605 DBUG_TRACE;
606 struct st_plugin_ctx *plugin_ctx = new st_plugin_ctx();
607
608 /* Open Session 1 */
609 WRITE_STR("Opening Session 1\n");
610 MYSQL_SESSION session = srv_session_open(NULL, plugin_ctx);
611 if (!session)
612 LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Open Session 1 failed.");
613
614 WRITE_SEP();
615
616 for (uint i = 0; i < 5; i++) {
617 WRITE_VAL("\nQuery %02d: ", i + 1);
618 exec_test_cmd(session, "SELECT * FROM test.t_int ORDER BY c1", p,
619 plugin_ctx);
620 WRITE_STR("\nDetach Session 1\n");
621 if (srv_session_detach(session))
622 LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Detach Session 1 failed.");
623 }
624
625 /* Close Session 1 */
626 WRITE_SEP();
627 WRITE_STR("Close Session 1\n");
628 if (srv_session_close(session))
629 LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "Close Session 1 failed.");
630
631 delete plugin_ctx;
632 }
633
634 struct test_thread_context {
635 my_thread_handle thread;
636 void *p;
637 bool thread_finished;
638 void (*test_function)(void *);
639 };
640
test_sql_threaded_wrapper(void * param)641 static void *test_sql_threaded_wrapper(void *param) {
642 char buffer[STRING_BUFFER_SIZE];
643 struct test_thread_context *context = (struct test_thread_context *)param;
644
645 WRITE_SEP();
646 WRITE_STR("init thread\n");
647 if (srv_session_init_thread(context->p))
648 LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
649 "srv_session_init_thread failed.");
650
651 context->test_function(context->p);
652
653 WRITE_STR("deinit thread\n");
654 srv_session_deinit_thread();
655
656 context->thread_finished = true;
657 return nullptr;
658 }
659
create_log_file(const char * log_name)660 static void create_log_file(const char *log_name) {
661 char filename[FN_REFLEN];
662
663 fn_format(filename, log_name, "", ".log",
664 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
665 unlink(filename);
666 outfile = my_open(filename, O_CREAT | O_RDWR, MYF(0));
667 }
668
test_in_spawned_thread(void * p,void (* test_function)(void *))669 static void test_in_spawned_thread(void *p, void (*test_function)(void *)) {
670 my_thread_attr_t attr; /* Thread attributes */
671 my_thread_attr_init(&attr);
672 (void)my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
673
674 struct test_thread_context context;
675
676 context.p = p;
677 context.thread_finished = false;
678 context.test_function = test_function;
679
680 /* now create the thread and call test_session within the thread. */
681 if (my_thread_create(&(context.thread), &attr, test_sql_threaded_wrapper,
682 &context) != 0)
683 LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
684 "Could not create test session thread");
685 else
686 my_thread_join(&context.thread, nullptr);
687 }
688
test_sql_service_plugin_init(void * p)689 static int test_sql_service_plugin_init(void *p) {
690 char buffer[STRING_BUFFER_SIZE];
691 DBUG_TRACE;
692 if (init_logging_service_for_plugin(®_srv, &log_bi, &log_bs)) return 1;
693 LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Installation.");
694
695 create_log_file(log_filename);
696
697 WRITE_SEP();
698 WRITE_STR("Test in a server thread\n");
699 test_sql(p);
700
701 /* Test in a new thread */
702 WRITE_STR("Follows threaded run\n");
703 test_in_spawned_thread(p, test_sql);
704
705 my_close(outfile, MYF(0));
706
707 return 0;
708 }
709
test_sql_service_plugin_deinit(void * p MY_ATTRIBUTE ((unused)))710 static int test_sql_service_plugin_deinit(void *p MY_ATTRIBUTE((unused))) {
711 DBUG_TRACE;
712 LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Uninstallation.");
713 deinit_logging_service_for_plugin(®_srv, &log_bi, &log_bs);
714 return 0;
715 }
716
717 struct st_mysql_daemon test_sql_service_plugin = {
718 MYSQL_DAEMON_INTERFACE_VERSION};
719
720 /*
721 Plugin library descriptor
722 */
723
mysql_declare_plugin(test_daemon)724 mysql_declare_plugin(test_daemon){
725 MYSQL_DAEMON_PLUGIN,
726 &test_sql_service_plugin,
727 "test_session_detach",
728 PLUGIN_AUTHOR_ORACLE,
729 "Test session detach",
730 PLUGIN_LICENSE_GPL,
731 test_sql_service_plugin_init, /* Plugin Init */
732 nullptr, /* Plugin Check uninstall */
733 test_sql_service_plugin_deinit, /* Plugin Deinit */
734 0x0100, /* 1.0 */
735 nullptr, /* status variables */
736 nullptr, /* system variables */
737 nullptr, /* config options */
738 0, /* flags */
739 } mysql_declare_plugin_end;
740