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