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