1 /* Copyright (c) 2015, 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
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include <stdlib.h>
24 #include <my_global.h>
25 #include "my_sys.h" // my_write, my_malloc
26 #include <mysql/plugin.h>
27 #include "mysql_com.h"
28 #include "m_string.h"
29 #include "sql_plugin.h" // st_plugin_int
30
31 #define STRING_BUFFER_SIZE 256
32
33 static const char *sep = "======================================================\n";
34
35 #define WRITE_SEP() my_write(outfile, (uchar*)sep, strlen(sep), MYF(0))
36
37 static File outfile;
38
WRITE_STR(const char * format)39 void WRITE_STR(const char *format)
40 {
41 char buffer[STRING_BUFFER_SIZE];
42 my_snprintf(buffer,sizeof(buffer),format);
43 my_write(outfile,(uchar*)buffer,strlen(buffer),MYF(0));
44 }
45
46
47 template<typename T>
WRITE_VAL(const char * format,T value)48 void WRITE_VAL(const char *format, T value)
49 {
50 char buffer[STRING_BUFFER_SIZE];
51 my_snprintf(buffer,sizeof(buffer),format,value);
52 my_write(outfile,(uchar*)buffer,strlen(buffer),MYF(0));
53 }
54
55
56 template<typename T1, typename T2>
WRITE_VAL(const char * format,T1 value1,T2 value2)57 void WRITE_VAL(const char *format, T1 value1, T2 value2)
58 {
59 char buffer[STRING_BUFFER_SIZE];
60 my_snprintf(buffer,sizeof(buffer),format,value1,value2);
61 my_write(outfile,(uchar*)buffer,strlen(buffer),MYF(0));
62 }
63
64
65 struct st_send_field_n
66 {
67 char db_name[256];
68 char table_name[256];
69 char org_table_name[256];
70 char col_name[256];
71 char org_col_name[256];
72 unsigned long length;
73 unsigned int charsetnr;
74 unsigned int flags;
75 unsigned int decimals;
76 enum_field_types type;
77 };
78
79
80 struct st_decimal_n {
81 int intg, frac, len;
82 my_bool sign;
83 decimal_digit_t buf[256];
84 };
85
86
87 struct st_plugin_ctx
88 {
89 const CHARSET_INFO *resultcs;
90 uint meta_server_status;
91 uint meta_warn_count;
92 uint current_col;
93 uint num_cols;
94 uint num_rows;
95 st_send_field_n sql_field[64];
96 char sql_str_value[64][64][256];
97 size_t sql_str_len[64][64];
98 longlong sql_int_value[64][64];
99 longlong sql_longlong_value[64][64];
100 uint sql_is_unsigned[64][64];
101 st_decimal_n sql_decimal_value[64][64];
102 double sql_double_value[64][64];
103 uint32 sql_double_decimals[64][64];
104 MYSQL_TIME sql_date_value[64][64];
105 MYSQL_TIME sql_time_value[64][64];
106 uint sql_time_decimals[64][64];
107 MYSQL_TIME sql_datetime_value[64][64];
108 uint sql_datetime_decimals[64][64];
109
110 uint server_status;
111 uint warn_count;
112 uint affected_rows;
113 uint last_insert_id;
114 char message[1024];
115
116 uint sql_errno;
117 char err_msg[1024];
118 char sqlstate[6];
st_plugin_ctxst_plugin_ctx119 st_plugin_ctx()
120 {
121 reset();
122 }
123
resetst_plugin_ctx124 void reset()
125 {
126 resultcs= NULL;
127 server_status= 0;
128 current_col= 0;
129 warn_count= 0;
130 num_cols= 0;
131 num_rows= 0;
132 memset(&sql_field, 0, 64 * sizeof(st_send_field_n));
133 memset(&sql_str_value, 0, 64 * 64 * 256 * sizeof(char));
134 memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
135 memset(&sql_int_value, 0, 64 * 64 * sizeof(longlong));
136 memset(&sql_longlong_value, 0, 64 * 64 * sizeof(longlong));
137 memset(&sql_is_unsigned, 0, 64 * 64 * sizeof(uint));
138 memset(&sql_decimal_value, 0, 64 * 64 * sizeof(st_decimal_n));
139 memset(&sql_double_value, 0, 64 * 64 * sizeof(double));
140 memset(&sql_double_decimals, 0, 64 * 64 * sizeof(uint32));
141 memset(&sql_date_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
142 memset(&sql_time_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
143 memset(&sql_time_decimals, 0, 64 * 64 * sizeof(uint));
144 memset(&sql_datetime_value, 0, 64 * 64 * sizeof(MYSQL_TIME));
145 memset(&sql_datetime_decimals, 0, 64 * 64 * sizeof(uint));
146
147 server_status= 0;
148 warn_count= 0;
149 affected_rows= 0;
150 last_insert_id= 0;
151 memset(&message, 0, sizeof(message));
152
153 sql_errno= 0;
154 memset(&err_msg, 0, sizeof(err_msg));
155 memset(&sqlstate, 0, sizeof(sqlstate));
156 }
157 };
158
159
sql_start_result_metadata(void * ctx,uint num_cols,uint flags,const CHARSET_INFO * resultcs)160 static int sql_start_result_metadata(void *ctx, uint num_cols, uint flags,
161 const CHARSET_INFO *resultcs)
162 {
163 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
164 DBUG_ENTER("sql_start_result_metadata");
165 DBUG_PRINT("info",("resultcs->number: %d", resultcs->number));
166 DBUG_PRINT("info",("resultcs->csname: %s", resultcs->csname));
167 DBUG_PRINT("info",("resultcs->name: %s", resultcs->name));
168 pctx->num_cols= num_cols;
169 pctx->resultcs= resultcs;
170 pctx->current_col= 0;
171 DBUG_RETURN(false);
172 }
173
174
sql_field_metadata(void * ctx,struct st_send_field * field,const CHARSET_INFO * charset)175 static int sql_field_metadata(void *ctx, struct st_send_field *field,
176 const CHARSET_INFO *charset)
177 {
178 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
179 st_send_field_n *cfield= &pctx->sql_field[pctx->current_col];
180 DBUG_ENTER("sql_field_metadata");
181 DBUG_PRINT("info",("field->db_name: %s", field->db_name));
182 DBUG_PRINT("info",("field->table_name: %s", field->table_name));
183 DBUG_PRINT("info",("field->org_table_name: %s", field->org_table_name));
184 DBUG_PRINT("info",("field->col_name: %s", field->col_name));
185 DBUG_PRINT("info",("field->org_col_name: %s", field->org_col_name));
186 DBUG_PRINT("info",("field->length: %d", (int)field->length));
187 DBUG_PRINT("info",("field->charsetnr: %d", (int)field->charsetnr));
188 DBUG_PRINT("info",("field->flags: %d", (int)field->flags));
189 DBUG_PRINT("info",("field->decimals: %d", (int)field->decimals));
190 DBUG_PRINT("info",("field->type: %d", (int)field->type));
191
192 strcpy(cfield->db_name, (char*)field->db_name);
193 strcpy(cfield->table_name, (char*)field->table_name);
194 strcpy(cfield->org_table_name, (char*)field->org_table_name);
195 strcpy(cfield->col_name, (char*)field->col_name);
196 strcpy(cfield->org_col_name, (char*)field->org_col_name);
197 cfield->length= field->length;
198 cfield->charsetnr= field->charsetnr;
199 cfield->flags= field->flags;
200 cfield->decimals= field->decimals;
201 cfield->type= field->type;
202
203 pctx->current_col++;
204 DBUG_RETURN(false);
205 }
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 {
211 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
212 DBUG_ENTER("sql_end_result_metadata");
213 pctx->meta_server_status= server_status;
214 pctx->meta_warn_count= warn_count;
215 pctx->num_rows= 0;
216 DBUG_RETURN(false);
217 }
218
219
sql_start_row(void * ctx)220 static int sql_start_row(void *ctx)
221 {
222 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
223 DBUG_ENTER("sql_start_row");
224 pctx->current_col= 0;
225 DBUG_RETURN(false);
226 }
227
228
sql_end_row(void * ctx)229 static int sql_end_row(void *ctx)
230 {
231 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
232 DBUG_ENTER("sql_end_row");
233 pctx->num_rows++;
234 DBUG_RETURN(false);
235 }
236
237
sql_abort_row(void * ctx)238 static void sql_abort_row(void *ctx)
239 {
240 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
241 DBUG_ENTER("sql_abort_row");
242 pctx->current_col= 0;
243 DBUG_VOID_RETURN;
244 };
245
246
sql_get_client_capabilities(void * ctx)247 static ulong sql_get_client_capabilities(void *ctx){
248 DBUG_ENTER("sql_get_client_capabilities");
249 DBUG_RETURN(0);
250 }
251
252
sql_get_null(void * ctx)253 static int sql_get_null(void *ctx)
254 {
255 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
256 DBUG_ENTER("sql_get_null");
257 uint row= pctx->num_rows;
258 uint col= pctx->current_col;
259 pctx->current_col++;
260
261 strcpy(pctx->sql_str_value[row][col], "[NULL]");
262 pctx->sql_str_len[row][col]= sizeof("[NULL]")-1;
263
264 DBUG_RETURN(false);
265 }
266
267
sql_get_integer(void * ctx,longlong value)268 static int sql_get_integer(void * ctx, longlong value)
269 {
270 char buffer[1024];
271 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
272 DBUG_ENTER("sql_get_integer");
273 uint row= pctx->num_rows;
274 uint col= pctx->current_col;
275 pctx->current_col++;
276
277 size_t len= my_snprintf(buffer, sizeof(buffer), "%d", value);
278
279 strncpy(pctx->sql_str_value[row][col], buffer, len);
280 pctx->sql_str_len[row][col]= len;
281 pctx->sql_int_value[row][col]= value;
282
283 DBUG_RETURN(false);
284 }
285
286
sql_get_longlong(void * ctx,longlong value,uint is_unsigned)287 static int sql_get_longlong(void * ctx, longlong value, uint is_unsigned)
288 {
289 char buffer[1024];
290 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
291 DBUG_ENTER("sql_get_longlong");
292 uint row= pctx->num_rows;
293 uint col= pctx->current_col;
294 pctx->current_col++;
295
296 size_t len= my_snprintf(buffer, sizeof(buffer),
297 is_unsigned? "%llu":"%lld", value);
298
299 strncpy(pctx->sql_str_value[row][col], buffer, len);
300 pctx->sql_str_len[row][col]= len;
301 pctx->sql_longlong_value[row][col]= value;
302 pctx->sql_is_unsigned[row][col]= is_unsigned;
303
304 DBUG_RETURN(false);
305 }
306
307
sql_get_decimal(void * ctx,const decimal_t * value)308 static int sql_get_decimal(void * ctx, const decimal_t * value)
309 {
310 char buffer[1024];
311 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
312 DBUG_ENTER("sql_get_decimal");
313 uint row= pctx->num_rows;
314 uint col= pctx->current_col;
315 pctx->current_col++;
316
317 size_t len= my_snprintf(buffer, sizeof(buffer),
318 "%s%d.%d(%d)[%s]",
319 value->sign? "+":"-",
320 value->intg, value->frac, value->len,
321 value->buf);
322
323 strncpy(pctx->sql_str_value[row][col], buffer, len);
324
325 pctx->sql_str_len[row][col]= len;
326 pctx->sql_decimal_value[row][col].intg= value->intg;
327 pctx->sql_decimal_value[row][col].frac= value->frac;
328 pctx->sql_decimal_value[row][col].len = value->len ;
329 pctx->sql_decimal_value[row][col].sign= value->sign;
330 memset((void*)pctx->sql_decimal_value[row][col].buf, '\0',(int)value->len);
331 memcpy((void*)pctx->sql_decimal_value[row][col].buf, (void*)value->buf,(int)value->len);
332
333 DBUG_RETURN(false);
334 }
335
336
sql_get_double(void * ctx,double value,uint32 decimals)337 static int sql_get_double(void * ctx, double value, uint32 decimals)
338 {
339 char buffer[1024];
340 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
341 DBUG_ENTER("sql_get_double");
342 uint row= pctx->num_rows;
343 uint col= pctx->current_col;
344 pctx->current_col++;
345
346 size_t len= my_snprintf(buffer, sizeof(buffer), "%3.7g", value);
347
348 strncpy(pctx->sql_str_value[row][col], buffer, len);
349 pctx->sql_str_len[row][col]= len;
350
351 pctx->sql_double_value[row][col]= value;
352 pctx->sql_double_decimals[row][col]= decimals;
353
354 DBUG_RETURN(false);
355 }
356
357
sql_get_date(void * ctx,const MYSQL_TIME * value)358 static int sql_get_date(void * ctx, const MYSQL_TIME * value)
359 {
360 char buffer[1024];
361 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
362 DBUG_ENTER("sql_get_date");
363 uint row= pctx->num_rows;
364 uint col= pctx->current_col;
365 pctx->current_col++;
366
367 size_t len= my_snprintf(buffer, sizeof(buffer),
368 "%s%4d-%02d-%02d",
369 value->neg? "-":"",
370 value->year, value->month, value->day);
371
372 strncpy(pctx->sql_str_value[row][col], buffer, len);
373 pctx->sql_str_len[row][col]= len;
374
375 pctx->sql_date_value[row][col].year= value->year;
376 pctx->sql_date_value[row][col].month= value->month;
377 pctx->sql_date_value[row][col].day= value->day;
378
379 pctx->sql_date_value[row][col].hour= value->hour;
380 pctx->sql_date_value[row][col].minute= value->minute;
381 pctx->sql_date_value[row][col].second= value->second;
382 pctx->sql_date_value[row][col].second_part= value->second_part;
383 pctx->sql_date_value[row][col].neg= value->neg;
384
385 DBUG_RETURN(false);
386 }
387
388
sql_get_time(void * ctx,const MYSQL_TIME * value,uint decimals)389 static int sql_get_time(void * ctx, const MYSQL_TIME * value, uint decimals)
390 {
391 char buffer[1024];
392 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
393 DBUG_ENTER("sql_get_time");
394 uint row= pctx->num_rows;
395 uint col= pctx->current_col;
396 pctx->current_col++;
397
398 size_t len= my_snprintf(buffer, sizeof(buffer),
399 "%s%02d:%02d:%02d",
400 value->neg? "-":"",
401 value->day? (value->day*24 + value->hour):value->hour,
402 value->minute, value->second);
403
404 strncpy(pctx->sql_str_value[row][col], buffer, len);
405 pctx->sql_str_len[row][col]= len;
406
407 pctx->sql_time_value[row][col].year= value->year;
408 pctx->sql_time_value[row][col].month= value->month;
409 pctx->sql_time_value[row][col].day= value->day;
410
411 pctx->sql_time_value[row][col].hour= value->hour;
412 pctx->sql_time_value[row][col].minute= value->minute;
413 pctx->sql_time_value[row][col].second= value->second;
414 pctx->sql_time_value[row][col].second_part= value->second_part;
415 pctx->sql_time_value[row][col].neg= value->neg;
416 pctx->sql_time_decimals[row][col]= decimals;
417
418 DBUG_RETURN(false);
419 }
420
421
sql_get_datetime(void * ctx,const MYSQL_TIME * value,uint decimals)422 static int sql_get_datetime(void * ctx, const MYSQL_TIME * value, uint decimals)
423 {
424 char buffer[1024];
425 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
426 DBUG_ENTER("sql_get_datetime");
427 uint row= pctx->num_rows;
428 uint col= pctx->current_col;
429 pctx->current_col++;
430
431 size_t len= my_snprintf(buffer, sizeof(buffer),
432 "%s%4d-%02d-%02d %02d:%02d:%02d",
433 value->neg? "-":"",
434 value->year, value->month, value->day,
435 value->hour, value->minute, value->second);
436
437 strncpy(pctx->sql_str_value[row][col], buffer, len);
438 pctx->sql_str_len[row][col]= len;
439
440 pctx->sql_datetime_value[row][col].year= value->year;
441 pctx->sql_datetime_value[row][col].month= value->month;
442 pctx->sql_datetime_value[row][col].day= value->day;
443
444 pctx->sql_datetime_value[row][col].hour= value->hour;
445 pctx->sql_datetime_value[row][col].minute= value->minute;
446 pctx->sql_datetime_value[row][col].second= value->second;
447 pctx->sql_datetime_value[row][col].second_part= value->second_part;
448 pctx->sql_datetime_value[row][col].neg= value->neg;
449 pctx->sql_datetime_decimals[row][col]= decimals;
450
451 DBUG_RETURN(false);
452 }
453
454
sql_get_string(void * ctx,const char * const value,size_t length,const CHARSET_INFO * const valuecs)455 static int sql_get_string(void * ctx, const char * const value, size_t length,
456 const CHARSET_INFO * const valuecs)
457 {
458 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
459 DBUG_ENTER("sql_get_string");
460 uint row= pctx->num_rows;
461 uint col= pctx->current_col;
462 pctx->current_col++;
463
464 strncpy(pctx->sql_str_value[row][col], value, length);
465 pctx->sql_str_len[row][col]= length;
466
467 DBUG_RETURN(false);
468 };
469
470
sql_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)471 static void sql_handle_ok(void * ctx,
472 uint server_status, uint statement_warn_count,
473 ulonglong affected_rows, ulonglong last_insert_id,
474 const char * const message)
475 {
476 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
477 DBUG_ENTER("sql_handle_ok");
478 /* This could be an EOF */
479 if (!pctx->num_cols)
480 pctx->num_rows= 0;
481 pctx->server_status= server_status;
482 pctx->warn_count= statement_warn_count;
483 pctx->affected_rows= affected_rows;
484 pctx->last_insert_id= last_insert_id;
485 if (message)
486 strncpy(pctx->message, message, sizeof(pctx->message));
487
488 DBUG_VOID_RETURN;
489 }
490
491
sql_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)492 static void sql_handle_error(void * ctx, uint sql_errno,
493 const char * const err_msg,
494 const char * const sqlstate)
495 {
496 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
497 DBUG_ENTER("sql_handle_error");
498 pctx->sql_errno=sql_errno;
499 if (pctx->sql_errno)
500 {
501 strcpy(pctx->err_msg, err_msg);
502 strcpy(pctx->sqlstate, sqlstate);
503 }
504 pctx->num_rows= 0;
505 DBUG_VOID_RETURN;
506 }
507
508
sql_shutdown(void * ctx,int shutdown_server)509 static void sql_shutdown(void *ctx, int shutdown_server)
510 {
511 DBUG_ENTER("sql_shutdown");
512 int *crashme = NULL;
513 *crashme = 0;
514 if (shutdown_server)
515 WRITE_STR("SERVER IS SHUTTING DOWN!!!\n");
516
517 DBUG_VOID_RETURN;
518 }
519
520
521 const struct st_command_service_cbs sql_cbs= {
522 sql_start_result_metadata,
523 sql_field_metadata,
524 sql_end_result_metadata,
525 sql_start_row,
526 sql_end_row,
527 sql_abort_row,
528 sql_get_client_capabilities,
529 sql_get_null,
530 sql_get_integer,
531 sql_get_longlong,
532 sql_get_decimal,
533 sql_get_double,
534 sql_get_date,
535 sql_get_time,
536 sql_get_datetime,
537 sql_get_string,
538 sql_handle_ok,
539 sql_handle_error,
540 sql_shutdown,
541 };
542
543
get_data_integer(void * ctx)544 static void get_data_integer(void * ctx)
545 {
546 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
547
548 /* get values */
549 if ((pctx->num_rows > 0) && (pctx->num_cols > 0))
550 {
551 for (uint col_count= 0; col_count < pctx->num_cols; col_count++)
552 {
553 WRITE_VAL("%s ", pctx->sql_field[col_count].col_name);
554 }
555 WRITE_STR("\n");
556
557 for (uint row_count= 0; row_count < pctx->num_rows; row_count++)
558 {
559 for (uint col_count= 0; col_count < pctx->num_cols; col_count++)
560 {
561 WRITE_VAL("%s ", pctx->sql_str_value[row_count][col_count]);
562 }
563 WRITE_STR("\n");
564 }
565 WRITE_STR("\n");
566
567 /* Metadata */
568 WRITE_VAL("num_cols : %d\n", pctx->num_cols);
569 WRITE_VAL("nb rows : %d\n", pctx->num_rows);
570 }
571 }
572
573
handle_error(void * ctx)574 static void handle_error(void * ctx)
575 {
576 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
577
578 /* handle_ok/error */
579 if (pctx->sql_errno)
580 {
581 WRITE_VAL("error: %d\n",pctx->sql_errno);
582 WRITE_VAL("error msg: %s\n",pctx->err_msg);
583 }
584 else
585 {
586 WRITE_VAL("affected rows : %d\n",pctx->affected_rows);
587 WRITE_VAL("server status : %d\n",pctx->server_status);
588 WRITE_VAL("warn count : %d\n",pctx->warn_count);
589 }
590 }
591
592 static bool callback_called= false;
593
error_callback(void * ctx,unsigned int sql_errno,const char * err_msg)594 static void error_callback(void *ctx, unsigned int sql_errno, const char *err_msg)
595 {
596 WRITE_VAL("ERROR %d : %s\n", sql_errno, err_msg);
597 callback_called= true;
598 }
599
600
exec_test_cmd(MYSQL_SESSION session,const char * test_cmd,void * p,void * ctx)601 static void exec_test_cmd(MYSQL_SESSION session, const char *test_cmd, void *p, void * ctx)
602 {
603 WRITE_VAL("%s\n",test_cmd);
604 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
605 COM_DATA cmd;
606
607 pctx->reset();
608 cmd.com_query.query= (char *)test_cmd;
609 cmd.com_query.length= strlen(cmd.com_query.query);
610 int fail= command_service_run_command(session,COM_QUERY,&cmd, &my_charset_utf8_general_ci,
611 &sql_cbs, CS_BINARY_REPRESENTATION, ctx);
612 if (fail)
613 {
614 if (callback_called == false)
615 my_plugin_log_message(&p, MY_ERROR_LEVEL, "Callback not called");
616 else
617 callback_called= false;
618 }
619 else
620 {
621 get_data_integer(ctx);
622 handle_error(ctx);
623 }
624 }
625
626
627 enum enum_init_cycle
628 {
629 FIRST_INIT= 1,
630 SECOND_INIT= 2
631 };
632
633 static enum enum_init_cycle plugin_init_cycle= FIRST_INIT;
634
test_sql(void * p)635 static void test_sql(void *p)
636 {
637 DBUG_ENTER("test_sql");
638 struct st_plugin_ctx *plugin_ctx= new st_plugin_ctx();
639 MYSQL_SESSION session;
640
641 /* Opening a Session */
642 WRITE_SEP();
643 WRITE_STR("Opening a Session\n");
644 session= srv_session_open(error_callback, plugin_ctx);
645 if (!session)
646 {
647 /*
648 We hope that this will always be okay. During the restart we will get here
649 before the server has started fully
650 */
651 if (srv_session_server_is_available() || !callback_called)
652 {
653 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_open failed");
654 delete plugin_ctx;
655 DBUG_VOID_RETURN;
656 }
657
658 while (!srv_session_server_is_available())
659 my_sleep(500);
660 plugin_init_cycle= SECOND_INIT;
661 }
662
663 WRITE_SEP();
664 if (plugin_init_cycle == FIRST_INIT)
665 {
666 while (srv_session_server_is_available())
667 my_sleep(500);
668
669 WRITE_STR("Apparently the server is shutting down\n");
670 }
671 exec_test_cmd(session, "SELECT 1, 2, 3 FROM DUAL", p, plugin_ctx);
672
673 /* Close Session */
674 WRITE_VAL("\nClosing Session. Plugin init cycle = %d\n\n", plugin_init_cycle);
675
676 srv_session_close(session);
677 delete plugin_ctx;
678
679 DBUG_VOID_RETURN;
680 }
681
682
683 struct test_services_context
684 {
685 my_thread_handle test_services_thread;
686 void *p;
687 };
688
689
test_sql_threaded_wrapper(void * param)690 static void* test_sql_threaded_wrapper(void *param)
691 {
692 struct test_services_context *context= (struct test_services_context*) param;
693
694 if (srv_session_init_thread(context->p))
695 my_plugin_log_message(&context->p, MY_ERROR_LEVEL, "srv_session_init_thread failed.");
696
697 test_sql(context->p);
698
699 srv_session_deinit_thread();
700
701 return NULL;
702 }
703
704
create_log_file(const char * log_name)705 static void create_log_file(const char * log_name)
706 {
707 char filename[FN_REFLEN];
708
709 fn_format(filename, log_name, "", ".log",
710 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
711 unlink(filename);
712 outfile= my_open(filename, O_CREAT|O_RDWR, MYF(0));
713 }
714
715
test_sql_service_plugin_init(void * p)716 static int test_sql_service_plugin_init(void *p)
717 {
718 DBUG_ENTER("test_sql_service_plugin_init");
719 my_plugin_log_message(&p, MY_INFORMATION_LEVEL, "Installation.");
720
721 create_log_file("test_sql_shutdown");
722
723 struct test_services_context *context;
724 my_thread_attr_t attr; /* Thread attributes */
725 my_thread_attr_init(&attr);
726 (void) my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
727
728 context= (struct test_services_context *)
729 my_malloc(PSI_INSTRUMENT_ME,
730 sizeof(struct test_services_context), MYF(0));
731 context->p= p;
732
733 callback_called= false;
734 /* now create the thread and call test_session within the thread. */
735 if (my_thread_create(&context->test_services_thread, &attr, test_sql_threaded_wrapper, context) != 0)
736 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_init_thread failed.");
737 else
738 ((struct st_plugin_int *) p)->data= (void*) context;
739
740 /* Now we can shut down the server */
741 DBUG_RETURN(0);
742 }
743
744
test_sql_service_plugin_deinit(void * p)745 static int test_sql_service_plugin_deinit(void *p)
746 {
747 struct test_services_context *con= (struct test_services_context *) ((struct st_plugin_int *) p)->data;
748 DBUG_ENTER("test_sql_service_plugin_deinit");
749
750 my_plugin_log_message(&p, MY_INFORMATION_LEVEL, "Uninstallation.");
751
752 WRITE_STR("SERVER SHUTDOWN\n");
753
754 if (con)
755 {
756 void *dummy_retval;
757 my_thread_cancel(&con->test_services_thread);
758 my_thread_join(&con->test_services_thread, &dummy_retval);
759 }
760 my_close(outfile, MYF(0));
761 my_free(con);
762 DBUG_RETURN(0);
763 }
764
765
766 struct st_mysql_daemon test_sql_service_plugin=
767 { MYSQL_DAEMON_INTERFACE_VERSION };
768
769
770 /*
771 Plugin library descriptor
772 */
773
mysql_declare_plugin(test_daemon)774 mysql_declare_plugin(test_daemon)
775 {
776 MYSQL_DAEMON_PLUGIN,
777 &test_sql_service_plugin,
778 "test_sql_shutdown",
779 "Horst Hunger, Andrey Hristov",
780 "Test SQL shutdown",
781 PLUGIN_LICENSE_GPL,
782 test_sql_service_plugin_init, /* Plugin Init */
783 test_sql_service_plugin_deinit, /* Plugin Deinit */
784 0x0100, /* 1.0 */
785 NULL, /* status variables */
786 NULL, /* system variables */
787 NULL, /* config options */
788 0, /* flags */
789 }
790 mysql_declare_plugin_end;
791