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