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