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(®_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(®_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