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