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 #include "sql_string.h" /* STRING_PSI_MEMORY_KEY */
30
31 static const char *log_filename= "test_sql_views_triggers";
32
33 struct st_test_statement
34 {
35 const char *db;
36 bool generates_result_set;
37 const char *query;
38 };
39
40
41 static struct st_test_statement test_query_plan[]=
42 {
43 /* DB RESULT QUERY */
44 { NULL , true , "SELECT 'first complex command' as a" },
45 /* View */
46 {"test", true , "SELECT * FROM v1" },
47 { NULL , true , "SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'v1'" },
48 {"test", false, "DROP VIEW v1" },
49 {"test", false, "CREATE VIEW v1 AS SELECT * FROM t1" },
50 {"test", true , "SELECT * FROM v1" },
51 /* Trigger */
52 {"test", false, "UPDATE t1 SET c2 = 'abcde' WHERE c1 = 1" },
53 {"test", true , "SELECT * FROM t2" },
54 { NULL , true , "SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = 'test' AND TRIGGER_NAME = 'trig'" },
55 {"test", false, "DROP TRIGGER trig" },
56 {"test", false, "CREATE TRIGGER trig AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t2 VALUES (1, 'aaa')" },
57 {"test", false, "UPDATE t1 SET c2 = 'abcde' WHERE c1 = 1" },
58 {"test", true , "SELECT * FROM t2" }
59 };
60
61 #define STRING_BUFFER_SIZE 512
62
63 #define WRITE_STR(format) \
64 { \
65 const size_t blen= my_snprintf(buffer, sizeof(buffer), (format)); \
66 my_write(outfile, (uchar*) buffer, blen, MYF(0)); \
67 /*pctx->log.append(buffer, blen); */ \
68 }
69
70
71 #define WRITE_VAL(format,value) \
72 { \
73 const size_t blen= my_snprintf(buffer, sizeof(buffer), (format), (value)); \
74 my_write(outfile,(uchar*)buffer, blen, MYF(0)); \
75 /* pctx->log.append(buffer, blen); */ \
76 }
77
78 #define WRITE_VAL2(format,value1, value2) \
79 { \
80 const size_t blen= my_snprintf(buffer, sizeof(buffer), (format), (value1), (value2)); \
81 my_write(outfile,(uchar*) buffer, blen, MYF(0)); \
82 /* pctx->log.append(buffer, blen); */ \
83 }
84
85 static const char *sep = "========================================================================\n";
86
87 #define WRITE_SEP() my_write(outfile, (uchar*)sep, strlen(sep), MYF(0))
88
89 static const char *user_localhost = "localhost";
90 static const char *user_local = "127.0.0.1";
91 static const char *user_db= "";
92 static const char *user_privileged= "root";
93 //static const char *user_ordinary= "ordinary";
94
switch_user(MYSQL_SESSION session,const char * user)95 static void switch_user(MYSQL_SESSION session, const char *user)
96 {
97 MYSQL_SECURITY_CONTEXT sc;
98 thd_get_security_context(srv_session_info_get_thd(session), &sc);
99 security_context_lookup(sc, user, user_localhost, user_local, user_db);
100 }
101
102 static File outfile;
103
104 struct st_send_field_n
105 {
106 char db_name[256];
107 char table_name[256];
108 char org_table_name[256];
109 char col_name[256];
110 char org_col_name[256];
111 unsigned long length;
112 unsigned int charsetnr;
113 unsigned int flags;
114 unsigned int decimals;
115 enum_field_types type;
116 };
117
118 #define SIZEOF_SQL_STR_VALUE 256
119
120 struct st_plugin_ctx
121 {
122 const CHARSET_INFO *resultcs;
123 uint meta_server_status;
124 uint meta_warn_count;
125 uint current_col;
126 uint num_cols;
127 uint num_rows;
128 st_send_field_n sql_field[64];
129 char sql_str_value[64][64][SIZEOF_SQL_STR_VALUE];
130 size_t sql_str_len[64][64];
131
132 uint server_status;
133 uint warn_count;
134 uint affected_rows;
135 uint last_insert_id;
136 char message[1024];
137
138 uint sql_errno;
139 char err_msg[1024];
140 char sqlstate[6];
141
142 std::string log;
st_plugin_ctxst_plugin_ctx143 st_plugin_ctx()
144 {
145 reset();
146 }
147
resetst_plugin_ctx148 void reset()
149 {
150 resultcs= NULL;
151 meta_server_status = 0;
152 meta_warn_count = 0;
153 server_status= 0;
154 current_col= 0;
155 warn_count= 0;
156 num_cols= 0;
157 num_rows= 0;
158 memset(&sql_field, 0, 64 * sizeof(st_send_field_n));
159 memset(&sql_str_value, 0, 64 * 64 * SIZEOF_SQL_STR_VALUE * sizeof(char));
160 memset(&sql_str_len, 0, 64 * 64 * sizeof(size_t));
161
162 server_status= 0;
163 warn_count= 0;
164 affected_rows= 0;
165 last_insert_id= 0;
166 memset(&message, 0, sizeof(message));
167
168 sql_errno= 0;
169 memset(&err_msg, 0, sizeof(err_msg));
170 memset(&sqlstate, 0, sizeof(sqlstate));
171
172 log.clear();
173 }
174 };
175
176
sql_start_result_metadata(void * ctx,uint num_cols,uint flags,const CHARSET_INFO * resultcs)177 static int sql_start_result_metadata(void *ctx, uint num_cols, uint flags,
178 const CHARSET_INFO *resultcs)
179 {
180 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
181 DBUG_ENTER("sql_start_result_metadata");
182 DBUG_PRINT("info",("resultcs->number: %d", resultcs->number));
183 DBUG_PRINT("info",("resultcs->csname: %s", resultcs->csname));
184 DBUG_PRINT("info",("resultcs->name: %s", resultcs->name));
185 pctx->num_cols= num_cols;
186 pctx->resultcs= resultcs;
187 pctx->current_col= 0;
188
189 DBUG_RETURN(false);
190 };
191
192
sql_field_metadata(void * ctx,struct st_send_field * field,const CHARSET_INFO * charset)193 static int sql_field_metadata(void *ctx, struct st_send_field *field,
194 const CHARSET_INFO *charset)
195 {
196 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
197 st_send_field_n *cfield= &pctx->sql_field[pctx->current_col];
198 DBUG_ENTER("sql_field_metadata");
199 DBUG_PRINT("info",("field->db_name: %s", field->db_name));
200 DBUG_PRINT("info",("field->table_name: %s", field->table_name));
201 DBUG_PRINT("info",("field->org_table_name: %s", field->org_table_name));
202 DBUG_PRINT("info",("field->col_name: %s", field->col_name));
203 DBUG_PRINT("info",("field->org_col_name: %s", field->org_col_name));
204 DBUG_PRINT("info",("field->length: %d", (int)field->length));
205 DBUG_PRINT("info",("field->charsetnr: %d", (int)field->charsetnr));
206 DBUG_PRINT("info",("field->flags: %d", (int)field->flags));
207 DBUG_PRINT("info",("field->decimals: %d", (int)field->decimals));
208 DBUG_PRINT("info",("field->type: %d", (int)field->type));
209
210 strcpy(cfield->db_name, (char*)field->db_name);
211 strcpy(cfield->table_name, (char*)field->table_name);
212 strcpy(cfield->org_table_name, (char*)field->org_table_name);
213 strcpy(cfield->col_name, (char*)field->col_name);
214 strcpy(cfield->org_col_name, (char*)field->org_col_name);
215 cfield->length= field->length;
216 cfield->charsetnr= field->charsetnr;
217 cfield->flags= field->flags;
218 cfield->decimals= field->decimals;
219 cfield->type= field->type;
220
221 pctx->current_col++;
222 DBUG_RETURN(false);
223 };
224
225
sql_end_result_metadata(void * ctx,uint server_status,uint warn_count)226 static int sql_end_result_metadata(void *ctx, uint server_status,
227 uint warn_count)
228 {
229 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
230 DBUG_ENTER("sql_end_result_metadata");
231 pctx->meta_server_status= server_status;
232 pctx->meta_warn_count= warn_count;
233 pctx->num_rows= 0;
234 DBUG_RETURN(false);
235 };
236
237
sql_start_row(void * ctx)238 static int sql_start_row(void *ctx)
239 {
240 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
241 DBUG_ENTER("sql_start_row");
242 pctx->current_col= 0;
243 DBUG_RETURN(false);
244 };
245
246
sql_end_row(void * ctx)247 static int sql_end_row(void *ctx)
248 {
249 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
250 DBUG_ENTER("sql_end_row");
251 pctx->num_rows++;
252 DBUG_RETURN(false);
253 };
254
255
sql_abort_row(void * ctx)256 static void sql_abort_row(void *ctx)
257 {
258 DBUG_ENTER("sql_abort_row");
259 DBUG_VOID_RETURN;
260 };
261
262
sql_get_client_capabilities(void * ctx)263 static ulong sql_get_client_capabilities(void *ctx)
264 {
265 DBUG_ENTER("sql_get_client_capabilities");
266 DBUG_RETURN(0);
267 };
268
269
sql_get_null(void * ctx)270 static int sql_get_null(void *ctx)
271 {
272 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
273 DBUG_ENTER("sql_get_null");
274 uint row= pctx->num_rows;
275 uint col= pctx->current_col;
276 pctx->current_col++;
277
278 strcpy(pctx->sql_str_value[row][col], "[NULL]");
279 pctx->sql_str_len[row][col]= sizeof("[NULL]")-1;
280
281 DBUG_RETURN(false);
282 };
283
284
sql_get_integer(void * ctx,longlong value)285 static int sql_get_integer(void * ctx, longlong value)
286 {
287 char buffer[1024];
288 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
289 DBUG_ENTER("sql_get_integer");
290 uint row= pctx->num_rows;
291 uint col= pctx->current_col;
292 pctx->current_col++;
293
294 size_t len= my_snprintf(buffer, sizeof(buffer), "%lld", value);
295
296 strncpy(pctx->sql_str_value[row][col], buffer, len);
297 pctx->sql_str_len[row][col]= len;
298
299 DBUG_RETURN(false);
300 };
301
302
sql_get_longlong(void * ctx,longlong value,uint is_unsigned)303 static int sql_get_longlong(void * ctx, longlong value, uint is_unsigned)
304 {
305 char buffer[1024];
306 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
307 DBUG_ENTER("sql_get_longlong");
308 uint row= pctx->num_rows;
309 uint col= pctx->current_col;
310 pctx->current_col++;
311
312 size_t len= my_snprintf(buffer, sizeof(buffer),
313 is_unsigned? "%llu":"%lld", value);
314
315 strncpy(pctx->sql_str_value[row][col], buffer, len);
316 pctx->sql_str_len[row][col]= len;
317
318 DBUG_RETURN(false);
319 };
320
321
test_decimal_as_string(char * buff,const decimal_t * val,int * length)322 static const char *test_decimal_as_string(char *buff, const decimal_t *val, int *length)
323 {
324 if (!val)
325 return "NULL";
326 (void)decimal2string(val, buff, length, 0,0,0);
327 return buff;
328 }
329
330
sql_get_decimal(void * ctx,const decimal_t * value)331 static int sql_get_decimal(void * ctx, const decimal_t * value)
332 {
333 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
334 DBUG_ENTER("sql_get_decimal");
335 uint row= pctx->num_rows;
336 uint col= pctx->current_col;
337 pctx->current_col++;
338
339 int len= SIZEOF_SQL_STR_VALUE;
340 test_decimal_as_string(pctx->sql_str_value[row][col], value, &len);
341 pctx->sql_str_len[row][col]= len;
342
343 DBUG_RETURN(false);
344 };
345
346
sql_get_double(void * ctx,double value,uint32 decimals)347 static int sql_get_double(void * ctx, double value, uint32 decimals)
348 {
349 char buffer[1024];
350 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
351 DBUG_ENTER("sql_get_double");
352 uint row= pctx->num_rows;
353 uint col= pctx->current_col;
354 pctx->current_col++;
355
356 size_t len= my_snprintf(buffer, sizeof(buffer), "%3.7g", value);
357
358 strncpy(pctx->sql_str_value[row][col], buffer, len);
359 pctx->sql_str_len[row][col]= len;
360
361 DBUG_RETURN(false);
362 };
363
364
sql_get_date(void * ctx,const MYSQL_TIME * value)365 static int sql_get_date(void * ctx, const MYSQL_TIME * value)
366 {
367 char buffer[1024];
368 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
369 DBUG_ENTER("sql_get_date");
370 uint row= pctx->num_rows;
371 uint col= pctx->current_col;
372 pctx->current_col++;
373
374 size_t len= my_snprintf(buffer, sizeof(buffer),
375 "%s%4d-%02d-%02d",
376 value->neg? "-":"",
377 value->year, value->month, value->day);
378
379 strncpy(pctx->sql_str_value[row][col], buffer, len);
380 pctx->sql_str_len[row][col]= len;
381
382 DBUG_RETURN(false);
383 };
384
385
sql_get_time(void * ctx,const MYSQL_TIME * value,uint decimals)386 static int sql_get_time(void * ctx, const MYSQL_TIME * value, uint decimals)
387 {
388 char buffer[1024];
389 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
390 DBUG_ENTER("sql_get_time");
391 uint row= pctx->num_rows;
392 uint col= pctx->current_col;
393 pctx->current_col++;
394
395 size_t len= my_snprintf(buffer, sizeof(buffer),
396 "%s%02d:%02d:%02d",
397 value->neg? "-":"",
398 value->day? (value->day*24 + value->hour):value->hour,
399 value->minute, value->second);
400
401 strncpy(pctx->sql_str_value[row][col], buffer, len);
402 pctx->sql_str_len[row][col]= len;
403 DBUG_RETURN(false);
404 };
405
406
sql_get_datetime(void * ctx,const MYSQL_TIME * value,uint decimals)407 static int sql_get_datetime(void * ctx, const MYSQL_TIME * value, uint decimals)
408 {
409 char buffer[1024];
410 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
411 DBUG_ENTER("sql_get_datetime");
412 uint row= pctx->num_rows;
413 uint col= pctx->current_col;
414 pctx->current_col++;
415
416 size_t len= my_snprintf(buffer, sizeof(buffer),
417 "%s%4d-%02d-%02d %02d:%02d:%02d",
418 value->neg? "-":"",
419 value->year, value->month, value->day,
420 value->hour, value->minute, value->second);
421
422 strncpy(pctx->sql_str_value[row][col], buffer, len);
423 pctx->sql_str_len[row][col]= len;
424
425
426 DBUG_RETURN(false);
427 };
428
429
sql_get_string(void * ctx,const char * const value,size_t length,const CHARSET_INFO * const valuecs)430 static int sql_get_string(void * ctx, const char * const value, size_t length,
431 const CHARSET_INFO * const valuecs)
432 {
433 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
434 DBUG_ENTER("sql_get_string");
435 uint row= pctx->num_rows;
436 uint col= pctx->current_col;
437 pctx->current_col++;
438
439 strncpy(pctx->sql_str_value[row][col], value, length);
440 pctx->sql_str_len[row][col]= length;
441
442 DBUG_RETURN(false);
443 };
444
445
sql_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)446 static void sql_handle_ok(void * ctx,
447 uint server_status, uint statement_warn_count,
448 ulonglong affected_rows, ulonglong last_insert_id,
449 const char * const message)
450 {
451 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
452 DBUG_ENTER("sql_handle_ok");
453 /* This could be an EOF */
454 if (!pctx->num_cols)
455 pctx->num_rows= 0;
456 pctx->server_status= server_status;
457 pctx->warn_count= statement_warn_count;
458 pctx->affected_rows= affected_rows;
459 pctx->last_insert_id= last_insert_id;
460 if (message)
461 strncpy(pctx->message, message, sizeof(pctx->message));
462
463 DBUG_VOID_RETURN;
464 };
465
466
sql_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)467 static void sql_handle_error(void * ctx, uint sql_errno,
468 const char * const err_msg,
469 const char * const sqlstate)
470 {
471 char buffer[1024];
472 struct st_plugin_ctx *pctx= (struct st_plugin_ctx*) ctx;
473 DBUG_ENTER("sql_handle_error");
474 WRITE_VAL2("[%u][%s]", sql_errno, sqlstate);
475 WRITE_VAL("[%s]", err_msg);
476 pctx->num_rows= 0;
477 DBUG_VOID_RETURN;
478 };
479
480
sql_shutdown(void * ctx,int shutdown_server)481 static void sql_shutdown(void *ctx, int shutdown_server)
482 {
483 DBUG_ENTER("sql_shutdown");
484 DBUG_VOID_RETURN;
485 };
486
487
488 const struct st_command_service_cbs protocol_callbacks=
489 {
490 sql_start_result_metadata,
491 sql_field_metadata,
492 sql_end_result_metadata,
493 sql_start_row,
494 sql_end_row,
495 sql_abort_row,
496 sql_get_client_capabilities,
497 sql_get_null,
498 sql_get_integer,
499 sql_get_longlong,
500 sql_get_decimal,
501 sql_get_double,
502 sql_get_date,
503 sql_get_time,
504 sql_get_datetime,
505 sql_get_string,
506 sql_handle_ok,
507 sql_handle_error,
508 sql_shutdown,
509 };
510
511 #define WRITE_DASHED_LINE() \
512 WRITE_STR("------------------------------------------------------------------\n");
513
fieldtype2str(enum enum_field_types type)514 static const char *fieldtype2str(enum enum_field_types type)
515 {
516 switch (type) {
517 case MYSQL_TYPE_BIT: return "BIT";
518 case MYSQL_TYPE_BLOB: return "BLOB";
519 case MYSQL_TYPE_DATE: return "DATE";
520 case MYSQL_TYPE_DATETIME: return "DATETIME";
521 case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL";
522 case MYSQL_TYPE_DECIMAL: return "DECIMAL";
523 case MYSQL_TYPE_DOUBLE: return "DOUBLE";
524 case MYSQL_TYPE_ENUM: return "ENUM";
525 case MYSQL_TYPE_FLOAT: return "FLOAT";
526 case MYSQL_TYPE_GEOMETRY: return "GEOMETRY";
527 case MYSQL_TYPE_INT24: return "INT24";
528 case MYSQL_TYPE_LONG: return "LONG";
529 case MYSQL_TYPE_LONGLONG: return "LONGLONG";
530 case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB";
531 case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB";
532 case MYSQL_TYPE_NEWDATE: return "NEWDATE";
533 case MYSQL_TYPE_NULL: return "NULL";
534 case MYSQL_TYPE_SET: return "SET";
535 case MYSQL_TYPE_SHORT: return "SHORT";
536 case MYSQL_TYPE_STRING: return "STRING";
537 case MYSQL_TYPE_TIME: return "TIME";
538 case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP";
539 case MYSQL_TYPE_TINY: return "TINY";
540 case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB";
541 case MYSQL_TYPE_VARCHAR: return "VARCHAR";
542 case MYSQL_TYPE_VAR_STRING: return "VAR_STRING";
543 case MYSQL_TYPE_YEAR: return "YEAR";
544 default: return "?-unknown-?";
545 }
546 }
547
548
fieldflags2str(uint f)549 static char *fieldflags2str(uint f)
550 {
551 static char buf[1024];
552 char *s=buf;
553 *s=0;
554 #define ff2s_check_flag(X) if (f & X ## _FLAG) { s=my_stpcpy(s, # X " "); f &= ~ X ## _FLAG; }
555 ff2s_check_flag(NOT_NULL);
556 ff2s_check_flag(PRI_KEY);
557 ff2s_check_flag(UNIQUE_KEY);
558 ff2s_check_flag(MULTIPLE_KEY);
559 ff2s_check_flag(BLOB);
560 ff2s_check_flag(UNSIGNED);
561 ff2s_check_flag(ZEROFILL);
562 ff2s_check_flag(BINARY);
563 ff2s_check_flag(ENUM);
564 ff2s_check_flag(AUTO_INCREMENT);
565 ff2s_check_flag(TIMESTAMP);
566 ff2s_check_flag(SET);
567 ff2s_check_flag(NO_DEFAULT_VALUE);
568 ff2s_check_flag(NUM);
569 ff2s_check_flag(PART_KEY);
570 ff2s_check_flag(GROUP);
571 ff2s_check_flag(UNIQUE);
572 ff2s_check_flag(BINCMP);
573 ff2s_check_flag(ON_UPDATE_NOW);
574 #undef ff2s_check_flag
575 if (f)
576 sprintf(s, " unknown=0x%04x", f);
577 return buf;
578 }
579
580
dump_meta_field(st_send_field_n field)581 static void dump_meta_field(st_send_field_n field)
582 {
583 char buffer[STRING_BUFFER_SIZE];
584
585 WRITE_VAL("\t\t\t[meta][field] db name: %s\n", field.db_name);
586 WRITE_VAL("\t\t\t[meta][field] table name: %s\n",field.table_name);
587 WRITE_VAL("\t\t\t[meta][field] org table name: %s\n",field.org_table_name);
588 WRITE_VAL("\t\t\t[meta][field] col name: %s\n", field.col_name);
589 WRITE_VAL("\t\t\t[meta][field] org col name: %s\n",field.org_col_name);
590 WRITE_VAL("\t\t\t[meta][field] length: %u\n",(uint)field.length);
591 WRITE_VAL("\t\t\t[meta][field] charsetnr: %u\n", field.charsetnr);
592
593 WRITE_VAL("\t\t\t[meta][field] flags: %u", field.flags);
594 if (field.flags)
595 WRITE_VAL(" (%s)", fieldflags2str(field.flags));
596 WRITE_STR("\n");
597
598 WRITE_VAL("\t\t\t[meta][field] decimals: %u\n", field.decimals);
599
600 WRITE_VAL2("\t\t\t[meta][field] type: %s (%u)\n",
601 fieldtype2str(field.type), field.type);
602 }
603
604
dump_cs_info(const CHARSET_INFO * cs)605 static void dump_cs_info(const CHARSET_INFO *cs)
606 {
607 char buffer[STRING_BUFFER_SIZE];
608 if (!cs)
609 {
610 WRITE_STR("\t\t[meta] no charset\n");
611 return;
612 }
613
614 WRITE_VAL("\t\t[meta][charset result] number: %d\n", cs->number);
615 WRITE_VAL("\t\t[meta][charset result] name: %s\n", cs->csname);
616 WRITE_VAL("\t\t[meta][charset result] collation: %s\n",cs->name);
617 WRITE_VAL("\t\t[meta][charset result] sort order: %s\n", cs->sort_order);
618 }
619
620
dump_decoded_server_status(const char * prefix,uint server_status)621 static void dump_decoded_server_status(const char *prefix, uint server_status)
622 {
623 char buffer[STRING_BUFFER_SIZE];
624 WRITE_STR(prefix);
625 WRITE_VAL("%u\n", server_status);
626 WRITE_STR(prefix);
627 for (int i= 0; i < 30; i++)
628 {
629 uint flag= 1 << i;
630 if (server_status & flag)
631 {
632 #define FLAG_DELIMITER " "
633 switch (flag) {
634 case SERVER_STATUS_IN_TRANS: WRITE_STR("IN_TRANS" FLAG_DELIMITER);break;
635 case SERVER_STATUS_AUTOCOMMIT: WRITE_STR("AUTOCOMMIT" FLAG_DELIMITER);break;
636 case SERVER_MORE_RESULTS_EXISTS: WRITE_STR("MORE_RESULTS_EXISTS" FLAG_DELIMITER);break;
637 case SERVER_QUERY_NO_GOOD_INDEX_USED: WRITE_STR("QUERY_NO_GOOD_INDEX_USED" FLAG_DELIMITER);break;
638 case SERVER_QUERY_NO_INDEX_USED: WRITE_STR("QUERY_NO_INDEX_USED" FLAG_DELIMITER);break;
639 case SERVER_STATUS_CURSOR_EXISTS: WRITE_STR("CURSOR_EXISTS" FLAG_DELIMITER);break;
640 case SERVER_STATUS_LAST_ROW_SENT: WRITE_STR("LAST_ROW_SENT" FLAG_DELIMITER);break;
641 case SERVER_STATUS_DB_DROPPED: WRITE_STR("DB_DROPPED" FLAG_DELIMITER);break;
642 case SERVER_STATUS_NO_BACKSLASH_ESCAPES:WRITE_STR("NO_BACKSLASH_ESCAPES" FLAG_DELIMITER);break;
643 case SERVER_STATUS_METADATA_CHANGED: WRITE_STR("METADATA_CHANGED" FLAG_DELIMITER);break;
644 case SERVER_QUERY_WAS_SLOW: WRITE_STR("QUERY_WAS_SLOW" FLAG_DELIMITER);break;
645 case SERVER_PS_OUT_PARAMS: WRITE_STR("PS_OUT_PARAMS" FLAG_DELIMITER);break;
646 case SERVER_STATUS_IN_TRANS_READONLY: WRITE_STR("IN_TRANS_READONLY" FLAG_DELIMITER);break;
647 case SERVER_SESSION_STATE_CHANGED: WRITE_STR("STATE_CHANGED" FLAG_DELIMITER);break;
648 default:
649 // Add a new flag defined in mysql_com.h above to fix this
650 WRITE_VAL("UNKNOWN_%u\n", flag);
651 }
652 #undef FLAG_DELIMITER
653 }
654 }
655 WRITE_STR("\n");
656 }
657
658
dump_meta_info(struct st_plugin_ctx * ctx)659 static void dump_meta_info(struct st_plugin_ctx *ctx)
660 {
661 char buffer[STRING_BUFFER_SIZE];
662
663 WRITE_VAL("\t\t[meta] rows: %u\n", ctx->num_rows);
664 WRITE_VAL("\t\t[meta] cols: %u\n", ctx->num_cols);
665 dump_decoded_server_status("\t\t[meta] server status: ", ctx->meta_server_status);
666 WRITE_VAL("\t\t[meta] warning count: %u\n", ctx->meta_warn_count);
667 WRITE_STR("\n");
668
669 if (!ctx->num_cols)
670 {
671 WRITE_STR("\t\t[meta] no columns\n");
672 }
673 else
674 for (uint col= 0; col < ctx->num_cols; col++)
675 {
676 dump_meta_field(ctx->sql_field[col]);
677 WRITE_STR("\n");
678 }
679
680 WRITE_STR("\n");
681
682 dump_cs_info(ctx->resultcs);
683 }
684
685
dump_result_set(struct st_plugin_ctx * ctx)686 static void dump_result_set(struct st_plugin_ctx *ctx)
687 {
688 char buffer[STRING_BUFFER_SIZE];
689
690 if (!ctx->num_rows)
691 WRITE_STR("\t\t[data] no rows\n");
692
693 for (uint row=0; row < ctx->num_rows; row++)
694 {
695 if (row)
696 WRITE_STR("\n");
697 for (uint col=0; col < ctx->num_cols; col++)
698 {
699 WRITE_VAL2("\t\t[data][%s.%s]", ctx->sql_field[col].table_name,
700 ctx->sql_field[col].col_name);
701 WRITE_VAL2("[%3u][%s]\n", (uint) ctx->sql_str_len[row][col],
702 ctx->sql_str_value[row][col]);
703 }
704 }
705 }
706
707
dump_closing_ok(struct st_plugin_ctx * ctx)708 static void dump_closing_ok(struct st_plugin_ctx *ctx)
709 {
710 char buffer[STRING_BUFFER_SIZE];
711
712 dump_decoded_server_status("\t\t[end] server status: ", ctx->server_status);
713 WRITE_VAL("\t\t[end] warning count: %u\n", ctx->warn_count);
714 WRITE_VAL("\t\t[end] affected rows: %u\n", ctx->affected_rows);
715 WRITE_VAL("\t\t[end] last insert id: %u\n", ctx->last_insert_id);
716 WRITE_VAL("\t\t[end] message: %s\n", ctx->message);
717 }
718
719
set_query_in_com_data(const char * query,union COM_DATA * cmd)720 static void set_query_in_com_data(const char *query, union COM_DATA *cmd)
721 {
722 char buffer[STRING_BUFFER_SIZE];
723
724 cmd->com_query.query= (char *) query;
725 cmd->com_query.length= strlen(query);
726 WRITE_VAL2("EXECUTING:[%u][%s]\n", cmd->com_query.length, query);\
727 }
728
729
run_statement(MYSQL_SESSION session,const char * query,struct st_plugin_ctx * ctx,bool generates_result_set,void * p)730 static void run_statement(MYSQL_SESSION session, const char *query,
731 struct st_plugin_ctx *ctx,
732 bool generates_result_set, void *p)
733 {
734 char buffer[STRING_BUFFER_SIZE];
735 COM_DATA cmd;
736
737 WRITE_DASHED_LINE();
738 set_query_in_com_data(query, &cmd);
739
740 enum cs_text_or_binary txt_or_bin= CS_TEXT_REPRESENTATION;
741
742 WRITE_STR("[CS_TEXT_REPRESENTATION]\n");
743 again:
744 ctx->reset();
745 int fail= command_service_run_command(session, COM_QUERY, &cmd,
746 &my_charset_utf8_general_ci,
747 &protocol_callbacks, txt_or_bin, ctx);
748 if (fail)
749 {
750 my_plugin_log_message(&p, MY_ERROR_LEVEL, "run_statement code: %d\n", fail);
751 return;
752 }
753
754 dump_meta_info(ctx); WRITE_STR("\n");
755
756 dump_result_set(ctx); WRITE_STR("\n");
757
758 dump_closing_ok(ctx);
759
760 if (generates_result_set && txt_or_bin == CS_TEXT_REPRESENTATION)
761 {
762 txt_or_bin= CS_BINARY_REPRESENTATION;
763 WRITE_STR("[CS_BINARY_REPRESENTATION]\n");
764 goto again;
765 }
766 }
767
768
change_current_db(MYSQL_SESSION session,const char * db,struct st_plugin_ctx * ctx,void * p)769 void static change_current_db(MYSQL_SESSION session, const char * db,
770 struct st_plugin_ctx *ctx, void *p)
771 {
772 char buffer[STRING_BUFFER_SIZE];
773 COM_DATA cmd;
774 cmd.com_init_db.db_name= db;
775 cmd.com_init_db.length= strlen(db);
776
777 WRITE_DASHED_LINE();
778 WRITE_VAL("EXECUTING:[COM_INIT_DB][%s]\n",db);
779 ctx->reset();
780 int fail= command_service_run_command(session, COM_INIT_DB, &cmd,
781 &my_charset_utf8_general_ci,
782 &protocol_callbacks,
783 CS_TEXT_REPRESENTATION,
784 ctx);
785 if (fail)
786 my_plugin_log_message(&p, MY_ERROR_LEVEL, "change db code: %d\n", fail);
787 }
788
789
test_selects(MYSQL_SESSION session,void * p)790 void test_selects(MYSQL_SESSION session, void *p)
791 {
792 DBUG_ENTER("test_selects");
793 char buffer[STRING_BUFFER_SIZE];
794
795 struct st_plugin_ctx *plugin_ctx= new st_plugin_ctx();
796
797 const char *last_db= NULL;
798 size_t stmt_count= sizeof(test_query_plan) / sizeof(test_query_plan[0]);
799 for (size_t i= 0; i < stmt_count; i++)
800 {
801 /* Change current DB if needed */
802 if (last_db != test_query_plan[i].db)
803 {
804 last_db= test_query_plan[i].db;
805
806 change_current_db(session, last_db? last_db:"", plugin_ctx, p);
807 }
808 run_statement(session, test_query_plan[i].query, plugin_ctx,
809 test_query_plan[i].generates_result_set, p);
810
811 last_db= NULL;
812 }
813
814 WRITE_DASHED_LINE();
815
816 delete plugin_ctx;
817 DBUG_VOID_RETURN;
818 }
819
820
test_sql(void * p)821 static void test_sql(void *p)
822 {
823 char buffer[STRING_BUFFER_SIZE];
824 DBUG_ENTER("test_sql");
825
826
827 WRITE_STR("[srv_session_open]\n");
828 MYSQL_SESSION session= srv_session_open(NULL, NULL);
829 if (!session)
830 {
831 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_open failed.");
832 DBUG_VOID_RETURN;
833 }
834
835 switch_user(session, user_privileged);
836
837 test_selects(session, p);
838
839 /* close session 1: Must pass */
840 WRITE_STR("[srv_session_close]\n");
841 if (srv_session_close(session))
842 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_close failed.");
843
844 DBUG_VOID_RETURN;
845 }
846
847
848 struct test_thread_context
849 {
850 my_thread_handle thread;
851 void *p;
852 bool thread_finished;
853 void (*test_function)(void *);
854 };
855
856
test_sql_threaded_wrapper(void * param)857 static void* test_sql_threaded_wrapper(void *param)
858 {
859 char buffer[STRING_BUFFER_SIZE];
860 struct test_thread_context *context= (struct test_thread_context*) param;
861
862 WRITE_SEP();
863 WRITE_STR("init thread\n");
864 if (srv_session_init_thread(context->p))
865 my_plugin_log_message(&context->p, MY_ERROR_LEVEL, "srv_session_init_thread failed.");
866
867 context->test_function(context->p);
868
869 WRITE_STR("deinit thread\n");
870 srv_session_deinit_thread();
871
872 context->thread_finished= true;
873 return NULL;
874 }
875
876
create_log_file(const char * log_name)877 static void create_log_file(const char * log_name)
878 {
879 char filename[FN_REFLEN];
880
881 fn_format(filename, log_name, "", ".log",
882 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
883 unlink(filename);
884 outfile= my_open(filename, O_CREAT|O_RDWR, MYF(0));
885 }
886
887
test_in_spawned_thread(void * p,void (* test_function)(void *))888 static void test_in_spawned_thread(void *p, void (*test_function)(void *))
889 {
890 my_thread_attr_t attr; /* Thread attributes */
891 my_thread_attr_init(&attr);
892 (void) my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
893
894 struct test_thread_context context;
895
896 context.p= p;
897 context.thread_finished= false;
898 context.test_function= test_function;
899
900 /* now create the thread and call test_session within the thread. */
901 if (my_thread_create(&(context.thread), &attr, test_sql_threaded_wrapper, &context) != 0)
902 my_plugin_log_message(&p, MY_ERROR_LEVEL, "Could not create test session thread");
903 else
904 my_thread_join(&context.thread, NULL);
905 }
906
test_sql_service_plugin_init(void * p)907 static int test_sql_service_plugin_init(void *p)
908 {
909 char buffer[STRING_BUFFER_SIZE];
910 DBUG_ENTER("test_sql_service_plugin_init");
911 my_plugin_log_message(&p, MY_INFORMATION_LEVEL, "Installation.");
912
913 create_log_file(log_filename);
914
915 WRITE_SEP();
916 WRITE_STR("Test in a server thread\n");
917 test_sql(p);
918
919 /* Test in a new thread */
920 WRITE_STR("Follows threaded run\n");
921 test_in_spawned_thread(p, test_sql);
922
923 my_close(outfile, MYF(0));
924
925 DBUG_RETURN(0);
926 }
927
test_sql_service_plugin_deinit(void * p)928 static int test_sql_service_plugin_deinit(void *p)
929 {
930 DBUG_ENTER("test_sql_service_plugin_deinit");
931 my_plugin_log_message(&p, MY_INFORMATION_LEVEL, "Uninstallation.");
932 DBUG_RETURN(0);
933 }
934
935
936 static struct st_mysql_daemon test_sql_service_plugin=
937 { MYSQL_DAEMON_INTERFACE_VERSION };
938
939
940 /*
941 Plugin library descriptor
942 */
943
mysql_declare_plugin(test_daemon)944 mysql_declare_plugin(test_daemon)
945 {
946 MYSQL_DAEMON_PLUGIN,
947 &test_sql_service_plugin,
948 "test_sql_views_triggers",
949 "Pavan Naik, Andrey Hristov",
950 "Test sql views triggers",
951 PLUGIN_LICENSE_GPL,
952 test_sql_service_plugin_init, /* Plugin Init */
953 test_sql_service_plugin_deinit, /* Plugin Deinit */
954 0x0100, /* 1.0 */
955 NULL, /* status variables */
956 NULL, /* system variables */
957 NULL, /* config options */
958 0, /* flags */
959 }
960 mysql_declare_plugin_end;
961