1 /* Copyright (c) 2015, 2020, 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 #define LOG_COMPONENT_TAG "test_sql_cmds_1"
24 
25 #include <fcntl.h>
26 #include <mysql/plugin.h>
27 #include <mysql/service_srv_session_info.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 
31 #include <mysql/components/my_service.h>
32 #include <mysql/components/services/log_builtins.h>
33 #include <mysqld_error.h>
34 
35 #include "my_dbug.h"
36 #include "my_inttypes.h"
37 #include "my_io.h"
38 #include "my_sys.h"     // my_write, my_malloc
39 #include "sql_string.h" /* STRING_PSI_MEMORY_KEY */
40 #include "template_utils.h"
41 #include "thr_cond.h"
42 
43 #define STRING_BUFFER 1024
44 
45 static const char *sep =
46     "======================================================\n";
47 
48 #define WRITE_SEP() \
49   my_write(outfile, pointer_cast<const uchar *>(sep), strlen(sep), MYF(0))
50 
51 static SERVICE_TYPE(registry) *reg_srv = nullptr;
52 SERVICE_TYPE(log_builtins) *log_bi = nullptr;
53 SERVICE_TYPE(log_builtins_string) *log_bs = nullptr;
54 
55 static File outfile;
56 
WRITE_STR(const char * format)57 static void WRITE_STR(const char *format) {
58   char buffer[STRING_BUFFER];
59   snprintf(buffer, sizeof(buffer), "%s", format);
60   my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0));
61 }
62 
63 template <typename T>
WRITE_VAL(const char * format,T value)64 void WRITE_VAL(const char *format, T value) {
65   char buffer[STRING_BUFFER];
66   snprintf(buffer, sizeof(buffer), format, value);
67   my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0));
68 }
69 
70 template <typename T1, typename T2>
WRITE_VAL(const char * format,T1 value1,T2 value2)71 void WRITE_VAL(const char *format, T1 value1, T2 value2) {
72   char buffer[STRING_BUFFER];
73   snprintf(buffer, sizeof(buffer), format, value1, value2);
74   my_write(outfile, (uchar *)buffer, strlen(buffer), MYF(0));
75 }
76 
77 static const char *user_localhost = "localhost";
78 static const char *user_local = "127.0.0.1";
79 static const char *user_db = "";
80 static const char *user_privileged = "root";
81 static const char *user_ordinary = "ordinary";
82 
switch_user(MYSQL_SESSION session,const char * user)83 static void switch_user(MYSQL_SESSION session, const char *user) {
84   MYSQL_SECURITY_CONTEXT sc;
85   thd_get_security_context(srv_session_info_get_thd(session), &sc);
86   security_context_lookup(sc, user, user_localhost, user_local, user_db);
87 }
88 
ensure_api_ok(const char * function,int result)89 static void ensure_api_ok(const char *function, int result) {
90   if (result != 0) {
91     WRITE_VAL("ERROR calling %s: returned %i\n", function, result);
92   }
93 }
94 
ensure_api_not_null(const char * function,void * result)95 static void ensure_api_not_null(const char *function, void *result) {
96   if (!result) {
97     WRITE_VAL("ERROR calling %s: returned NULL\n", function);
98   }
99 }
100 #define ENSURE_API_OK(call) ensure_api_ok(__FUNCTION__, (call));
101 #define ENSURE_API_NOT_NULL(call) ensure_api_not_null(__FUNCTION__, (call));
102 
103 struct Callback_data {
104   int err;
105   std::string errmsg;
106   std::string sqlstate;
107   bool error_called;
108 
109   int server_status;
110   uint warn_count;
111   uint affected_rows;
112   uint last_insert_id;
113   std::string message;
114 
115   int shutdown;
116   bool shutdown_called;
117 
Callback_dataCallback_data118   Callback_data() { reset(); }
119 
resetCallback_data120   void reset() {
121     error_called = false;
122     errmsg.clear();
123     sqlstate.clear();
124     message.clear();
125     err = 0;
126     server_status = 0;
127     warn_count = 0;
128     affected_rows = 0;
129     last_insert_id = 0;
130     shutdown = 0;
131     shutdown_called = false;
132   }
133 };
134 
135 struct st_send_field_n {
136   char db_name[256];
137   char table_name[256];
138   char org_table_name[256];
139   char col_name[256];
140   char org_col_name[256];
141   unsigned long length;
142   unsigned int charsetnr;
143   unsigned int flags;
144   unsigned int decimals;
145   enum_field_types type;
146 };
147 
148 const CHARSET_INFO *sql_resultcs = nullptr;
149 uint sql_num_meta_rows = 0;
150 uint sql_num_rows = 0;
151 uint col_count = 0;
152 uint sql_num_cols = 0;
153 uint sql_flags = 0;
154 st_send_field_n sql_field[64][64];
155 
156 int row_count = 0;
157 
sql_start_result_metadata(void *,uint num_cols,uint,const CHARSET_INFO * resultcs)158 static int sql_start_result_metadata(void *, uint num_cols, uint,
159                                      const CHARSET_INFO *resultcs) {
160   DBUG_TRACE;
161   DBUG_PRINT("info", ("resultcs->number: %d", resultcs->number));
162   DBUG_PRINT("info", ("resultcs->csname: %s", resultcs->csname));
163   DBUG_PRINT("info", ("resultcs->name: %s", resultcs->name));
164   row_count = 0;
165   sql_num_cols = num_cols;
166   sql_resultcs = resultcs;
167   return false;
168 }
169 
sql_field_metadata(void *,struct st_send_field * field,const CHARSET_INFO *)170 static int sql_field_metadata(void *, struct st_send_field *field,
171                               const CHARSET_INFO *) {
172   DBUG_TRACE;
173   DBUG_PRINT("info", ("field->db_name: %s", field->db_name));
174   DBUG_PRINT("info", ("field->table_name: %s", field->table_name));
175   DBUG_PRINT("info", ("field->org_table_name: %s", field->org_table_name));
176   DBUG_PRINT("info", ("field->col_name: %s", field->col_name));
177   DBUG_PRINT("info", ("field->org_col_name: %s", field->org_col_name));
178   DBUG_PRINT("info", ("field->length: %d", (int)field->length));
179   DBUG_PRINT("info", ("field->charsetnr: %d", (int)field->charsetnr));
180   DBUG_PRINT("info", ("field->flags: %d", (int)field->flags));
181   DBUG_PRINT("info", ("field->decimals: %d", (int)field->decimals));
182   DBUG_PRINT("info", ("field->type: %d", (int)field->type));
183   strcpy(sql_field[col_count][row_count].db_name, field->db_name);
184   strcpy(sql_field[col_count][row_count].table_name, field->table_name);
185   strcpy(sql_field[col_count][row_count].org_table_name, field->org_table_name);
186   strcpy(sql_field[col_count][row_count].col_name, field->col_name);
187   strcpy(sql_field[col_count][row_count].org_col_name, field->org_col_name);
188   sql_field[col_count][row_count].length = field->length;
189   sql_field[col_count][row_count].charsetnr = field->charsetnr;
190   sql_field[col_count][row_count].flags = field->flags;
191   sql_field[col_count][row_count].decimals = field->decimals;
192   sql_field[col_count][row_count].type = field->type;
193   return false;
194 }
195 
sql_end_result_metadata(void *,uint,uint)196 static int sql_end_result_metadata(void *, uint, uint) {
197   DBUG_TRACE;
198   sql_num_meta_rows = row_count;
199   row_count = 0;
200   return false;
201 }
202 
sql_start_row(void *)203 static int sql_start_row(void *) {
204   DBUG_TRACE;
205   col_count = 0;
206   return false;
207 }
208 
sql_end_row(void *)209 static int sql_end_row(void *) {
210   DBUG_TRACE;
211   row_count++;
212   return false;
213 }
214 
sql_abort_row(void *)215 static void sql_abort_row(void *) { DBUG_TRACE; }
216 
sql_get_client_capabilities(void *)217 static ulong sql_get_client_capabilities(void *) {
218   DBUG_TRACE;
219   return 0;
220 }
221 
sql_get_null(void *)222 static int sql_get_null(void *) {
223   DBUG_TRACE;
224   return false;
225 }
226 
sql_get_integer(void *,longlong)227 static int sql_get_integer(void *, longlong) {
228   DBUG_TRACE;
229   return false;
230 }
231 
sql_get_longlong(void *,longlong,uint)232 static int sql_get_longlong(void *, longlong, uint) {
233   DBUG_TRACE;
234   return false;
235 }
236 
sql_get_decimal(void *,const decimal_t *)237 static int sql_get_decimal(void *, const decimal_t *) {
238   DBUG_TRACE;
239   return false;
240 }
241 
sql_get_double(void *,double,uint32)242 static int sql_get_double(void *, double, uint32) {
243   DBUG_TRACE;
244   return false;
245 }
246 
sql_get_date(void *,const MYSQL_TIME *)247 static int sql_get_date(void *, const MYSQL_TIME *) {
248   DBUG_TRACE;
249   return false;
250 }
251 
sql_get_time(void *,const MYSQL_TIME *,uint)252 static int sql_get_time(void *, const MYSQL_TIME *, uint) {
253   DBUG_TRACE;
254   return false;
255 }
256 
sql_get_datetime(void *,const MYSQL_TIME *,uint)257 static int sql_get_datetime(void *, const MYSQL_TIME *, uint) {
258   DBUG_TRACE;
259   return false;
260 }
261 
262 char sql_str_value[64][64][256];
263 size_t sql_str_len[64][64];
264 
sql_get_string(void *,const char * const value,size_t length,const CHARSET_INFO * const)265 static int sql_get_string(void *, const char *const value, size_t length,
266                           const CHARSET_INFO *const) {
267   DBUG_TRACE;
268   strncpy(sql_str_value[col_count][row_count], value, length);
269   sql_str_len[col_count][row_count] = length;
270   col_count++;
271   return false;
272 }
273 
sql_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)274 static void sql_handle_ok(void *ctx, uint server_status,
275                           uint statement_warn_count, ulonglong affected_rows,
276                           ulonglong last_insert_id, const char *const message) {
277   DBUG_TRACE;
278 
279   Callback_data *cbd = (Callback_data *)ctx;
280 
281   cbd->server_status = server_status;
282   cbd->warn_count = statement_warn_count;
283   cbd->affected_rows = affected_rows;
284   cbd->last_insert_id = last_insert_id;
285   cbd->message = message ? message : "";
286 }
287 
sql_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)288 static void sql_handle_error(void *ctx, uint sql_errno,
289                              const char *const err_msg,
290                              const char *const sqlstate) {
291   DBUG_TRACE;
292   Callback_data *cbd = (Callback_data *)ctx;
293   WRITE_VAL("ERROR %i %s\n", sql_errno, err_msg);
294   cbd->error_called = true;
295   cbd->err = sql_errno;
296   cbd->errmsg = err_msg ? err_msg : "";
297   cbd->sqlstate = sqlstate ? sqlstate : "";
298 }
299 
sql_shutdown(void * ctx,int shutdown_server)300 static void sql_shutdown(void *ctx, int shutdown_server) {
301   DBUG_TRACE;
302   Callback_data *cbd = (Callback_data *)ctx;
303 
304   cbd->shutdown = shutdown_server;
305   cbd->shutdown_called = true;
306 }
307 
308 const struct st_command_service_cbs sql_cbs = {
309     sql_start_result_metadata,
310     sql_field_metadata,
311     sql_end_result_metadata,
312     sql_start_row,
313     sql_end_row,
314     sql_abort_row,
315     sql_get_client_capabilities,
316     sql_get_null,
317     sql_get_integer,
318     sql_get_longlong,
319     sql_get_decimal,
320     sql_get_double,
321     sql_get_date,
322     sql_get_time,
323     sql_get_datetime,
324     sql_get_string,
325     sql_handle_ok,
326     sql_handle_error,
327     sql_shutdown,
328 };
329 
330 /****************************************************************************************/
331 
test_com_query(void * p MY_ATTRIBUTE ((unused)))332 static void test_com_query(void *p MY_ATTRIBUTE((unused))) {
333   DBUG_TRACE;
334 
335   /* Session declarations */
336   MYSQL_SESSION st_session;
337   void *plugin_ctx = nullptr;
338   bool session_ret = false;
339   bool fail = false;
340   COM_DATA cmd;
341   Callback_data cbd;
342 
343   WRITE_STR("COM_QUERY");
344 
345   /* Open session 1: Must pass */
346   st_session = srv_session_open(NULL, plugin_ctx);
347   if (!st_session) {
348     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "srv_session_open failed.");
349   } else
350     switch_user(st_session, user_privileged);
351 
352   WRITE_STR(
353       "-----------------------------------------------------------------\n");
354   memset(&sql_str_value, 0, 64 * 64 * 256 * sizeof(char));
355   memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
356   cmd.com_query.query = "SELECT id,info FROM information_schema.processlist";
357   cmd.com_query.length = strlen(cmd.com_query.query);
358   WRITE_VAL("%s\n", cmd.com_query.query);
359   fail = command_service_run_command(st_session, COM_QUERY, &cmd,
360                                      &my_charset_utf8_general_ci, &sql_cbs,
361                                      CS_TEXT_REPRESENTATION, &cbd);
362   if (fail)
363     LogPluginErrMsg(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "sql_simple ret code: %d\n",
364                     fail);
365   else {
366     /* get values */
367     WRITE_STR(
368         "-----------------------------------------------------------------\n");
369     WRITE_VAL("%s\t\%s\n", sql_field[0][0].col_name, sql_field[0][1].col_name);
370     for (uint row = 0; row < sql_num_rows; row++) {
371       for (uint col = 0; col < sql_num_cols; col++) {
372         WRITE_VAL("%s\n", sql_str_value[col][row]);
373       }
374     }
375     /* start metadata */
376     WRITE_VAL("num_cols: %d\n", sql_num_cols);
377     /* end metadata */
378     if (cbd.err) {
379       WRITE_VAL("error: %d\n", cbd.err);
380       WRITE_VAL("error msg: %s\n", cbd.errmsg.c_str());
381     } else {
382       WRITE_VAL("server status: %d\n", cbd.server_status);
383       WRITE_VAL("warn count: %d\n", cbd.warn_count);
384       //           WRITE_VAL("messsage: %s\n",msg);
385     }
386   }
387 
388   /* 2. statement */
389   WRITE_STR(
390       "-----------------------------------------------------------------\n");
391   memset(&sql_str_value, 0, 64 * 64 * 256 * sizeof(char));
392   memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
393   cmd.com_query.query =
394       "SELECT * FROM performance_schema.global_variables WHERE variable_name "
395       "LIKE 'INNODB_READ_IO_THREADS'";
396   cmd.com_query.length = strlen(cmd.com_query.query);
397   WRITE_VAL("%s\n", cmd.com_query.query);
398   cbd.reset();
399   fail = command_service_run_command(st_session, COM_QUERY, &cmd,
400                                      &my_charset_utf8_general_ci, &sql_cbs,
401                                      CS_TEXT_REPRESENTATION, &cbd);
402   if (fail)
403     LogPluginErrMsg(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "sql_simple ret code: %d\n",
404                     fail);
405   else {
406     /* get values */
407     WRITE_STR(
408         "-----------------------------------------------------------------\n");
409     WRITE_VAL("%s\t\%s\n", sql_field[0][0].col_name, sql_field[0][1].col_name);
410     for (uint row = 0; row < sql_num_rows; row++) {
411       for (uint col = 0; col < sql_num_cols; col += 2) {
412         WRITE_VAL("%s\t\%s\n", sql_str_value[col][row],
413                   sql_str_value[col + 1][row]);
414       }
415     }
416   }
417   /* start metadata */
418   WRITE_VAL("num_cols: %d\n", sql_num_cols);
419   /* end metadata */
420   if (cbd.err) {
421     WRITE_VAL("error: %d\n", cbd.err);
422     WRITE_VAL("error msg: %s\n", cbd.errmsg.c_str());
423   } else {
424     WRITE_VAL("server status: %d\n", cbd.server_status);
425     WRITE_VAL("warn count: %d\n", cbd.warn_count);
426   }
427 
428   // 3. statement must fail
429   cbd.reset();
430   cmd.com_query.query = "garbage";
431   cmd.com_query.length = strlen(cmd.com_query.query);
432 
433   ENSURE_API_OK(command_service_run_command(
434       st_session, COM_QUERY, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
435       CS_TEXT_REPRESENTATION, &cbd));
436 
437   WRITE_VAL("error after bad SQL: %i: %s\n", cbd.err, cbd.errmsg.c_str());
438 
439   /* close session 1: Must pass */
440   WRITE_STR("srv_session_close.\n");
441   session_ret = srv_session_close(st_session);
442   if (session_ret)
443     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "srv_session_close failed.");
444 }
445 
test_com_init_db(void * p)446 static int test_com_init_db(void *p) {
447   DBUG_TRACE;
448 
449   MYSQL_SESSION st_session;
450 
451   ENSURE_API_NOT_NULL(st_session = srv_session_open(NULL, p));
452 
453   if (st_session) switch_user(st_session, user_privileged);
454   COM_DATA cmd;
455 
456   LEX_CSTRING db_name = srv_session_info_get_current_db(st_session);
457   WRITE_VAL("current_db before init_db : %s\n", db_name.str);
458 
459   cmd.com_init_db.db_name = "mysql";
460   cmd.com_init_db.length = strlen("mysql");
461   Callback_data cbd;
462   ENSURE_API_OK(command_service_run_command(
463       st_session, COM_INIT_DB, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
464       CS_TEXT_REPRESENTATION, &cbd));
465 
466   db_name = srv_session_info_get_current_db(st_session);
467   WRITE_VAL("current_db after init_db  : %s\n", db_name.str);
468 
469   ENSURE_API_OK(srv_session_close(st_session));
470 
471   return 0;
472 }
473 
474 /*
475 static int test_com_list_fields(void *p)
476 {
477   DBUG_TRACE;
478 
479   MYSQL_SESSION st_session;
480 
481   ENSURE_API_NOT_NULL(st_session = srv_session_open(NULL, p));
482 
483   COM_DATA cmd;
484 
485   cmd.com_init_db.db_name = "mysql";
486   cmd.com_init_db.length = strlen("mysql");
487   ENSURE_API_OK(command_service_run_command(st_session, COM_INIT_DB, &cmd,
488 &my_charset_utf8_general_ci, &sql_cbs, CS_TEXT_REPRESENTATION, p));
489 
490   WRITE_VAL("switched default db to: %s\n",
491 srv_session_info_get_current_db(st_session));
492 
493 
494   WRITE_STR("field_list\n");
495   cmd.com_field_list.table_name = (unsigned char*)"user";
496   cmd.com_field_list.table_name_length = strlen((const
497 char*)cmd.com_field_list.table_name); cmd.com_field_list.query = (unsigned
498 char*)"%"; cmd.com_field_list.query_length = strlen((const
499 char*)cmd.com_field_list.query);
500   ENSURE_API_OK(command_service_run_command(st_session, COM_FIELD_LIST, &cmd,
501 &my_charset_utf8_general_ci, &sql_cbs, CS_TEXT_REPRESENTATION, p));
502 
503   WRITE_STR("-----------------------------------------------------------------\n");
504   for (uint row_count=0;row_count < sql_num_rows;row_count++){
505     for (uint col_count=0;col_count < sql_num_cols;col_count+=2){
506       WRITE_VAL("%s\t\%s\n",sql_str_value[col_count][row_count],
507                   sql_str_value[col_count+1][row_count]);
508     }
509   }
510 
511   ENSURE_API_OK(srv_session_close(st_session));
512 
513   return 0;
514 }
515 */
516 
517 struct Test_data {
518   void *p;
519   MYSQL_SESSION session;
520   native_mutex_t mutex;
521   native_cond_t cond;
522   int ready;
523 
Test_dataTest_data524   Test_data() {
525     ready = 0;
526     native_cond_init(&cond);
527     native_mutex_init(&mutex, nullptr);
528   }
529 
~Test_dataTest_data530   ~Test_data() {
531     native_cond_destroy(&cond);
532     native_mutex_destroy(&mutex);
533   }
534 
waitTest_data535   void wait(int value) {
536     native_mutex_lock(&mutex);
537     while (ready < value) native_cond_wait(&cond, &mutex);
538     native_mutex_unlock(&mutex);
539   }
540 
goTest_data541   void go() {
542     native_mutex_lock(&mutex);
543     ready++;
544     native_cond_signal(&cond);
545     native_mutex_unlock(&mutex);
546   }
547 };
548 
test_session_thread(Test_data * tdata)549 static void *test_session_thread(Test_data *tdata) {
550   COM_DATA cmd;
551   Callback_data cbdata;
552 
553   if (srv_session_init_thread(tdata->p))
554     LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
555                  "srv_session_init_thread failed.");
556 
557   WRITE_VAL("session is dead? %i\n",
558             thd_killed(srv_session_info_get_thd(tdata->session)));
559 
560   cmd.com_query.query = "select sleep(10)";
561   cmd.com_query.length = strlen("select sleep(10)");
562 
563   WRITE_VAL("Executing %s\n", cmd.com_query.query);
564 
565   tdata->go();
566 
567   int r = command_service_run_command(tdata->session, COM_QUERY, &cmd,
568                                       &my_charset_utf8_general_ci, &sql_cbs,
569                                       CS_TEXT_REPRESENTATION, &cbdata);
570   WRITE_VAL("Killed run_command return value: %i\n", r);
571 
572   WRITE_VAL("thread shutdown: %i (%s)\n", cbdata.shutdown,
573             cbdata.shutdown_called ? "yes" : "no");
574   WRITE_VAL("thread error: %i\n", cbdata.err);
575   WRITE_VAL("thread error msg: %s\n", cbdata.errmsg.c_str());
576 
577   WRITE_VAL("session is dead (after)? %i\n",
578             thd_killed(srv_session_info_get_thd(tdata->session)));
579 
580   srv_session_detach(tdata->session);
581 
582   srv_session_deinit_thread();
583 
584   return nullptr;
585 }
586 
session_error_cb(void *,unsigned int sql_errno,const char * err_msg)587 static void session_error_cb(void *, unsigned int sql_errno,
588                              const char *err_msg) {
589   WRITE_STR("default error handler called\n");
590   WRITE_VAL("sql_errno = %i\n", sql_errno);
591   WRITE_VAL("errmsg = %s\n", err_msg);
592 }
593 
test_query_kill(void * p)594 static int test_query_kill(void *p) {
595   DBUG_TRACE;
596 
597   MYSQL_SESSION st_session;
598 
599   WRITE_STR("test_query_kill\n");
600 
601   ENSURE_API_NOT_NULL(st_session = srv_session_open(NULL, p));
602 
603   switch_user(st_session, user_privileged);
604   MYSQL_SESSION st_session_victim;
605   ENSURE_API_NOT_NULL(st_session_victim =
606                           srv_session_open(session_error_cb, p));
607 
608   Test_data tdata;
609 
610   tdata.p = p;
611   tdata.session = st_session_victim;
612 
613   my_thread_handle thread_handle;
614   {
615     my_thread_attr_t attr;
616 
617     my_thread_attr_init(&attr);
618     (void)my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
619 
620     if (my_thread_create(&thread_handle, &attr,
621                          (void *(*)(void *))test_session_thread, &tdata) != 0) {
622       WRITE_STR("Could not create test services thread!\n");
623       exit(1);
624     }
625   }
626 
627   // wait for thread to be ready
628   tdata.wait(1);
629 
630   COM_DATA cmd;
631   Callback_data cbd;
632 
633   sleep(1);
634   char buffer[200];
635   snprintf(buffer, sizeof(buffer), "kill query %i",
636            srv_session_info_get_session_id(st_session_victim));
637   WRITE_STR("run KILL QUERY\n");
638   cmd.com_query.query = buffer;
639   cmd.com_query.length = strlen(buffer);
640   ENSURE_API_OK(command_service_run_command(
641       st_session, COM_QUERY, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
642       CS_TEXT_REPRESENTATION, &cbd));
643 
644   void *ret;
645   my_thread_join(&thread_handle, &ret);
646   WRITE_STR("OK\n");
647 
648   ENSURE_API_OK(srv_session_close(st_session));
649   ENSURE_API_OK(srv_session_close(st_session_victim));
650 
651   return 0;
652 }
653 
test_com_process_kill(void * p)654 static int test_com_process_kill(void *p) {
655   DBUG_TRACE;
656 
657   MYSQL_SESSION st_session;
658   Callback_data cbd;
659 
660   WRITE_STR("COM_KILL\n");
661 
662   ENSURE_API_NOT_NULL(st_session = srv_session_open(NULL, p));
663 
664   switch_user(st_session, user_privileged);
665   MYSQL_SESSION st_session_victim;
666   ENSURE_API_NOT_NULL(st_session_victim =
667                           srv_session_open(session_error_cb, p));
668 
669   WRITE_VAL("session is dead? %i\n",
670             thd_killed(srv_session_info_get_thd(st_session_victim)));
671 
672   COM_DATA cmd;
673 
674   cmd.com_kill.id = srv_session_info_get_session_id(st_session_victim);
675   ENSURE_API_OK(command_service_run_command(
676       st_session, COM_PROCESS_KILL, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
677       CS_TEXT_REPRESENTATION, &cbd));
678 
679   WRITE_VAL("session is dead now? %i\n",
680             thd_killed(srv_session_info_get_thd(st_session_victim)));
681 
682   ENSURE_API_OK(srv_session_close(st_session));
683   ENSURE_API_OK(srv_session_close(st_session_victim));
684 
685   return 0;
686 }
687 
test_priv(void * p)688 static int test_priv(void *p) {
689   DBUG_TRACE;
690 
691   MYSQL_SESSION root_session;
692   Callback_data cbd;
693   COM_DATA cmd;
694 
695   WRITE_STR("COM_QUERY with priv\n");
696 
697   ENSURE_API_NOT_NULL(root_session = srv_session_open(NULL, p));
698 
699   switch_user(root_session, user_privileged);
700 
701   cmd.com_query.query = "create user ordinary@localhost";
702   cmd.com_query.length = strlen(cmd.com_query.query);
703   ENSURE_API_OK(command_service_run_command(
704       root_session, COM_QUERY, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
705       CS_TEXT_REPRESENTATION, &cbd));
706   WRITE_VAL("create user as root: %i %s\n", cbd.err, cbd.errmsg.c_str());
707 
708   WRITE_STR("now try as ordinary user\n");
709   {
710     MYSQL_SESSION ordinary_session;
711     ENSURE_API_NOT_NULL(ordinary_session = srv_session_open(NULL, p));
712     switch_user(ordinary_session, user_ordinary);
713 
714     cbd.reset();
715     cmd.com_query.query = "create user bogus@localhost";
716     cmd.com_query.length = strlen(cmd.com_query.query);
717     ENSURE_API_OK(command_service_run_command(
718         ordinary_session, COM_QUERY, &cmd, &my_charset_utf8_general_ci,
719         &sql_cbs, CS_TEXT_REPRESENTATION, &cbd));
720 
721     WRITE_VAL("create user supposed to fail: %i %s\n", cbd.err,
722               cbd.errmsg.c_str());
723 
724     ENSURE_API_OK(srv_session_close(ordinary_session));
725   }
726 
727   cbd.reset();
728   cmd.com_query.query = "drop user ordinary@localhost";
729   cmd.com_query.length = strlen(cmd.com_query.query);
730   ENSURE_API_OK(command_service_run_command(
731       root_session, COM_QUERY, &cmd, &my_charset_utf8_general_ci, &sql_cbs,
732       CS_TEXT_REPRESENTATION, &cbd));
733   WRITE_VAL("drop user as root: %i %s\n", cbd.err, cbd.errmsg.c_str());
734 
735   ENSURE_API_OK(srv_session_close(root_session));
736 
737   return 0;
738 }
739 
test_sql(void * p MY_ATTRIBUTE ((unused)))740 static void test_sql(void *p MY_ATTRIBUTE((unused))) {
741   DBUG_TRACE;
742   LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Installation.");
743 
744   WRITE_SEP();
745   test_com_query(p);
746   WRITE_SEP();
747   test_com_init_db(p);
748   WRITE_SEP();
749   //  test_com_list_fields(p);
750   //  WRITE_SEP();
751   test_com_process_kill(p);
752   WRITE_SEP();
753   test_query_kill(p);
754   WRITE_SEP();
755   test_priv(p);
756 }
757 
create_log_file(const char * log_name)758 static void create_log_file(const char *log_name) {
759   char filename[FN_REFLEN];
760 
761   fn_format(filename, log_name, "", ".log",
762             MY_REPLACE_EXT | MY_UNPACK_FILENAME);
763   unlink(filename);
764   outfile = my_open(filename, O_CREAT | O_RDWR, MYF(0));
765 }
766 
767 static const char *log_filename = "test_sql_cmds_1";
768 
test_sql_service_plugin_init(void * p)769 static int test_sql_service_plugin_init(void *p) {
770   DBUG_TRACE;
771   if (init_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs)) return 1;
772   LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Installation.");
773 
774   create_log_file(log_filename);
775 
776   /* Test of service: sql */
777   test_sql(p);
778 
779   my_close(outfile, MYF(0));
780   return 0;
781 }
782 
test_sql_service_plugin_deinit(void * p MY_ATTRIBUTE ((unused)))783 static int test_sql_service_plugin_deinit(void *p MY_ATTRIBUTE((unused))) {
784   DBUG_TRACE;
785   LogPluginErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, "Uninstallation.");
786   deinit_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs);
787   return 0;
788 }
789 
790 struct st_mysql_daemon test_sql_service_plugin = {
791     MYSQL_DAEMON_INTERFACE_VERSION};
792 
793 /*
794   Plugin library descriptor
795 */
796 
mysql_declare_plugin(test_daemon)797 mysql_declare_plugin(test_daemon){
798     MYSQL_DAEMON_PLUGIN,
799     &test_sql_service_plugin,
800     "test_sql_cmds_1",
801     PLUGIN_AUTHOR_ORACLE,
802     "Test sql service commands",
803     PLUGIN_LICENSE_GPL,
804     test_sql_service_plugin_init,   /* Plugin Init */
805     nullptr,                        /* Plugin Check uninstall */
806     test_sql_service_plugin_deinit, /* Plugin Deinit */
807     0x0100 /* 1.0 */,
808     nullptr, /* status variables                */
809     nullptr, /* system variables                */
810     nullptr, /* config options                  */
811     0,       /* flags                           */
812 } mysql_declare_plugin_end;
813