1 /* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights
2 * reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
23
24 #include <my_global.h>
25 #include <my_sys.h>
26 #include "my_default.h"
27 #include <mysql.h>
28 #include <errmsg.h>
29 #include <my_getopt.h>
30 #include <m_string.h>
31 #include <mysqld_error.h>
32 #include <sql_common.h>
33 #include <mysql/client_plugin.h>
34
35 #define VER "2.1"
36 #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
37 #define MAX_KEY MAX_INDEXES
38 #define MAX_SERVER_ARGS 64
39
40 /* set default options */
41 static int opt_testcase = 0;
42 static char *opt_db= 0;
43 static char *opt_user= 0;
44 static char *opt_password= 0;
45 static char *opt_host= 0;
46 static char *opt_unix_socket= 0;
47 #ifdef HAVE_SMEM
48 static char *shared_memory_base_name= 0;
49 #endif
50 static unsigned int opt_port;
51 static my_bool tty_password= 0, opt_silent= 0;
52
53 static my_bool opt_secure_auth= 1;
54 static MYSQL *mysql= 0;
55 static char current_db[]= "client_test_db";
56 static unsigned int test_count= 0;
57 static unsigned int opt_count= 0;
58 static unsigned int opt_count_read= 0;
59 static unsigned int iter_count= 0;
60 static my_bool have_innodb= FALSE;
61 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
62 static unsigned int opt_drop_db= 1;
63
64 static const char *opt_basedir= "./";
65 static const char *opt_vardir= "mysql-test/var";
66
67 static longlong opt_getopt_ll_test= 0;
68
69 static char **defaults_argv;
70 static int original_argc;
71 static char **original_argv;
72 static int embedded_server_arg_count= 0;
73 static char *embedded_server_args[MAX_SERVER_ARGS];
74
75 static const char *embedded_server_groups[]= {
76 "server",
77 "embedded",
78 "mysql_client_test_SERVER",
79 NullS
80 };
81
82 static time_t start_time, end_time;
83 static double total_time;
84
85 const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace";
86
87 /*
88 Read and parse arguments and MySQL options from my.cnf
89 */
90 static const char *client_test_load_default_groups[]= { "client", 0 };
91
92 struct my_tests_st
93 {
94 const char *name;
95 void (*function)();
96 };
97
98 #define myheader(str) \
99 DBUG_PRINT("test", ("name: %s", str)); \
100 if (opt_silent < 2) \
101 { \
102 fprintf(stdout, "\n\n#####################################\n"); \
103 fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \
104 opt_count, str); \
105 fprintf(stdout, " \n#####################################\n"); \
106 }
107
108 #define myheader_r(str) \
109 DBUG_PRINT("test", ("name: %s", str)); \
110 if (!opt_silent) \
111 { \
112 fprintf(stdout, "\n\n#####################################\n"); \
113 fprintf(stdout, "%s", str); \
114 fprintf(stdout, " \n#####################################\n"); \
115 }
116
117 static void print_error(MYSQL * l_mysql, const char *msg);
118 static void print_st_error(MYSQL_STMT *stmt, const char *msg);
119 static void client_disconnect(MYSQL* mysql);
120 static void get_options(int *argc, char ***argv);
121
122 /*
123 Abort unless given experssion is non-zero.
124
125 SYNOPSIS
126 DIE_UNLESS(expr)
127
128 DESCRIPTION
129 We can't use any kind of system assert as we need to
130 preserve tested invariants in release builds as well.
131 */
132
133 #define DIE_UNLESS(expr) \
134 ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0)))
135 #define DIE_IF(expr) \
136 ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0))
137 #define DIE(expr) \
138 die(__FILE__, __LINE__, #expr)
139
die(const char * file,int line,const char * expr)140 static void die(const char *file, int line, const char *expr)
141 {
142 fflush(stdout);
143 fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr);
144 fflush(stderr);
145 exit(1);
146 }
147
148
149 #define myerror(msg) print_error(mysql,msg)
150 #define myerror2(l_mysql, msg) print_error(l_mysql,msg)
151 #define mysterror(stmt, msg) print_st_error(stmt, msg)
152
153 #define myquery(RES) \
154 { \
155 int r= (RES); \
156 if (r) \
157 myerror(NULL); \
158 DIE_UNLESS(r == 0); \
159 }
160
161 #define myquery2(L_MYSQL,RES) \
162 { \
163 int r= (RES); \
164 if (r) \
165 myerror2(L_MYSQL,NULL); \
166 DIE_UNLESS(r == 0); \
167 }
168
169 #define myquery_r(r) \
170 { \
171 if (r) \
172 myerror(NULL); \
173 DIE_UNLESS(r != 0); \
174 }
175
176 #define check_execute(stmt, r) \
177 { \
178 if (r) \
179 mysterror(stmt, NULL); \
180 DIE_UNLESS(r == 0); \
181 }
182
183 #define check_execute_r(stmt, r) \
184 { \
185 if (r) \
186 mysterror(stmt, NULL); \
187 DIE_UNLESS(r != 0); \
188 }
189
190 #define check_stmt(stmt) \
191 { \
192 if ( stmt == 0) \
193 myerror(NULL); \
194 DIE_UNLESS(stmt != 0); \
195 }
196
197 #define check_stmt_r(stmt) \
198 { \
199 if (stmt == 0) \
200 myerror(NULL); \
201 DIE_UNLESS(stmt == 0); \
202 }
203
204 #define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);}
205 #define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);}
206
207
208 /* A workaround for Sun Forte 5.6 on Solaris x86 */
209
cmp_double(double * a,double * b)210 static int cmp_double(double *a, double *b)
211 {
212 return *a == *b;
213 }
214
215
216 /* Print the error message */
217
print_error(MYSQL * l_mysql,const char * msg)218 static void print_error(MYSQL *l_mysql, const char *msg)
219 {
220 if (!opt_silent)
221 {
222 if (l_mysql && mysql_errno(l_mysql))
223 {
224 if (l_mysql->server_version)
225 fprintf(stdout, "\n [MySQL-%s]", l_mysql->server_version);
226 else
227 fprintf(stdout, "\n [MySQL]");
228 fprintf(stdout, "[%d] %s\n", mysql_errno(l_mysql), mysql_error(l_mysql));
229 }
230 else if (msg)
231 fprintf(stderr, " [MySQL] %s\n", msg);
232 }
233 }
234
235
print_st_error(MYSQL_STMT * stmt,const char * msg)236 static void print_st_error(MYSQL_STMT *stmt, const char *msg)
237 {
238 if (!opt_silent)
239 {
240 if (stmt && mysql_stmt_errno(stmt))
241 {
242 if (stmt->mysql && stmt->mysql->server_version)
243 fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version);
244 else
245 fprintf(stdout, "\n [MySQL]");
246
247 fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt),
248 mysql_stmt_error(stmt));
249 }
250 else if (msg)
251 fprintf(stderr, " [MySQL] %s\n", msg);
252 }
253 }
254
255 /*
256 Enhanced version of mysql_client_init(), which may also set shared memory
257 base on Windows.
258 */
mysql_client_init(MYSQL * con)259 static MYSQL *mysql_client_init(MYSQL* con)
260 {
261 MYSQL* res = mysql_init(con);
262 #ifdef HAVE_SMEM
263 if (res && shared_memory_base_name)
264 mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name);
265 #endif
266 if (opt_plugin_dir && *opt_plugin_dir)
267 mysql_options(res, MYSQL_PLUGIN_DIR, opt_plugin_dir);
268
269 if (opt_default_auth && *opt_default_auth)
270 mysql_options(res, MYSQL_DEFAULT_AUTH, opt_default_auth);
271
272 if (!opt_secure_auth)
273 mysql_options(res, MYSQL_SECURE_AUTH, (char*)&opt_secure_auth);
274 return res;
275 }
276
277 /*
278 Disable direct calls of mysql_init, as it disregards shared memory base.
279 */
280 #define mysql_init(A) Please use mysql_client_init instead of mysql_init
281
282
283 /* Check if the connection has InnoDB tables */
284
check_have_innodb(MYSQL * conn)285 static my_bool check_have_innodb(MYSQL *conn)
286 {
287 MYSQL_RES *res;
288 MYSQL_ROW row;
289 int rc;
290 my_bool result= FALSE;
291
292 rc= mysql_query(conn,
293 "SELECT (support = 'YES' or support = 'DEFAULT' or support = 'ENABLED') "
294 "AS `TRUE` FROM information_schema.engines WHERE engine = 'innodb'");
295 myquery(rc);
296 res= mysql_use_result(conn);
297 DIE_UNLESS(res);
298
299 row= mysql_fetch_row(res);
300 DIE_UNLESS(row);
301
302 if (row[0] && row[1])
303 result= strcmp(row[1], "1") == 0;
304 mysql_free_result(res);
305 return result;
306 }
307
308
309 /*
310 This is to be what mysql_query() is for mysql_real_query(), for
311 mysql_simple_prepare(): a variant without the 'length' parameter.
312 */
313
314 static MYSQL_STMT *STDCALL
mysql_simple_prepare(MYSQL * mysql_arg,const char * query)315 mysql_simple_prepare(MYSQL *mysql_arg, const char *query)
316 {
317 MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg);
318 if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query)))
319 {
320 mysql_stmt_close(stmt);
321 return 0;
322 }
323 return stmt;
324 }
325
326
327 /**
328 Connect to the server with options given by arguments to this application,
329 stored in global variables opt_host, opt_user, opt_password, opt_db,
330 opt_port and opt_unix_socket.
331
332 @param flag[in] client_flag passed on to mysql_real_connect
333 @param protocol[in] MYSQL_PROTOCOL_* to use for this connection
334 @param auto_reconnect[in] set to 1 for auto reconnect
335
336 @return pointer to initialized and connected MYSQL object
337 */
client_connect(ulong flag,uint protocol,my_bool auto_reconnect)338 static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect)
339 {
340 MYSQL* mysql;
341 int rc;
342 static char query[MAX_TEST_QUERY_LENGTH];
343 myheader_r("client_connect");
344
345 if (!opt_silent)
346 fprintf(stdout, "\n Establishing a connection to '%s' ...",
347 opt_host ? opt_host : "");
348
349 if (!(mysql= mysql_client_init(NULL)))
350 {
351 opt_silent= 0;
352 myerror("mysql_client_init() failed");
353 exit(1);
354 }
355 /* enable local infile, in non-binary builds often disabled by default */
356 mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0);
357 mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol);
358 if (opt_plugin_dir && *opt_plugin_dir)
359 mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
360
361 if (opt_default_auth && *opt_default_auth)
362 mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
363
364 if (!opt_secure_auth)
365 mysql_options(mysql, MYSQL_SECURE_AUTH, (char*)&opt_secure_auth);
366
367 if (!(mysql_real_connect(mysql, opt_host, opt_user,
368 opt_password, opt_db ? opt_db:"test", opt_port,
369 opt_unix_socket, flag)))
370 {
371 opt_silent= 0;
372 myerror("connection failed");
373 mysql_close(mysql);
374 fprintf(stdout, "\n Check the connection options using --help or -?\n");
375 exit(1);
376 }
377 mysql->reconnect= auto_reconnect;
378
379 if (!opt_silent)
380 fprintf(stdout, "OK");
381
382 /* set AUTOCOMMIT to ON*/
383 mysql_autocommit(mysql, TRUE);
384
385 if (!opt_silent)
386 {
387 fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n",
388 mysql_get_server_info(mysql),
389 (ulong) mysql_get_server_version(mysql));
390 fprintf(stdout, "\n Creating a test database '%s' ...", current_db);
391 }
392 strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS);
393
394 rc= mysql_query(mysql, query);
395 myquery(rc);
396
397 strxmov(query, "USE ", current_db, NullS);
398 rc= mysql_query(mysql, query);
399 myquery(rc);
400 have_innodb= check_have_innodb(mysql);
401
402 if (!opt_silent)
403 fprintf(stdout, "OK");
404
405 return mysql;
406 }
407
408
409 /* Close the connection */
410
client_disconnect(MYSQL * mysql)411 static void client_disconnect(MYSQL* mysql)
412 {
413 static char query[MAX_TEST_QUERY_LENGTH];
414
415 myheader_r("client_disconnect");
416
417 if (mysql)
418 {
419 if (opt_drop_db)
420 {
421 if (!opt_silent)
422 fprintf(stdout, "\n dropping the test database '%s' ...", current_db);
423 strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS);
424
425 mysql_query(mysql, query);
426 if (!opt_silent)
427 fprintf(stdout, "OK");
428 }
429
430 if (!opt_silent)
431 fprintf(stdout, "\n closing the connection ...");
432 mysql_close(mysql);
433 if (!opt_silent)
434 fprintf(stdout, "OK\n");
435 }
436 }
437
438
439 /* Print dashes */
440
my_print_dashes(MYSQL_RES * result)441 static void my_print_dashes(MYSQL_RES *result)
442 {
443 MYSQL_FIELD *field;
444 unsigned int i, j;
445
446 mysql_field_seek(result, 0);
447 fputc('\t', stdout);
448 fputc('+', stdout);
449
450 for(i= 0; i< mysql_num_fields(result); i++)
451 {
452 field= mysql_fetch_field(result);
453 for(j= 0; j < field->max_length+2; j++)
454 fputc('-', stdout);
455 fputc('+', stdout);
456 }
457 fputc('\n', stdout);
458 }
459
460
461 /* Print resultset metadata information */
462
my_print_result_metadata(MYSQL_RES * result)463 static void my_print_result_metadata(MYSQL_RES *result)
464 {
465 MYSQL_FIELD *field;
466 unsigned int i, j;
467 unsigned int field_count;
468
469 mysql_field_seek(result, 0);
470 if (!opt_silent)
471 {
472 fputc('\n', stdout);
473 fputc('\n', stdout);
474 }
475
476 field_count= mysql_num_fields(result);
477 for(i= 0; i< field_count; i++)
478 {
479 field= mysql_fetch_field(result);
480 j= strlen(field->name);
481 if (j < field->max_length)
482 j= field->max_length;
483 if (j < 4 && !IS_NOT_NULL(field->flags))
484 j= 4;
485 field->max_length= j;
486 }
487 if (!opt_silent)
488 {
489 my_print_dashes(result);
490 fputc('\t', stdout);
491 fputc('|', stdout);
492 }
493
494 mysql_field_seek(result, 0);
495 for(i= 0; i< field_count; i++)
496 {
497 field= mysql_fetch_field(result);
498 if (!opt_silent)
499 fprintf(stdout, " %-*s |", (int) field->max_length, field->name);
500 }
501 if (!opt_silent)
502 {
503 fputc('\n', stdout);
504 my_print_dashes(result);
505 }
506 }
507
508
509 /* Process the result set */
510
my_process_result_set(MYSQL_RES * result)511 static int my_process_result_set(MYSQL_RES *result)
512 {
513 MYSQL_ROW row;
514 MYSQL_FIELD *field;
515 unsigned int i;
516 unsigned int row_count= 0;
517
518 if (!result)
519 return 0;
520
521 my_print_result_metadata(result);
522
523 while ((row= mysql_fetch_row(result)) != NULL)
524 {
525 mysql_field_seek(result, 0);
526 if (!opt_silent)
527 {
528 fputc('\t', stdout);
529 fputc('|', stdout);
530 }
531
532 for(i= 0; i< mysql_num_fields(result); i++)
533 {
534 field= mysql_fetch_field(result);
535 if (!opt_silent)
536 {
537 if (row[i] == NULL)
538 fprintf(stdout, " %-*s |", (int) field->max_length, "NULL");
539 else if (IS_NUM(field->type))
540 fprintf(stdout, " %*s |", (int) field->max_length, row[i]);
541 else
542 fprintf(stdout, " %-*s |", (int) field->max_length, row[i]);
543 }
544 }
545 if (!opt_silent)
546 {
547 fputc('\t', stdout);
548 fputc('\n', stdout);
549 }
550 row_count++;
551 }
552 if (!opt_silent)
553 {
554 if (row_count)
555 my_print_dashes(result);
556
557 if (mysql_errno(mysql) != 0)
558 fprintf(stderr, "\n\tmysql_fetch_row() failed\n");
559 else
560 fprintf(stdout, "\n\t%d %s returned\n", row_count,
561 row_count == 1 ? "row" : "rows");
562 }
563 return row_count;
564 }
565
566
my_process_result(MYSQL * mysql_arg)567 static int my_process_result(MYSQL *mysql_arg)
568 {
569 MYSQL_RES *result;
570 int row_count;
571
572 if (!(result= mysql_store_result(mysql_arg)))
573 return 0;
574
575 row_count= my_process_result_set(result);
576
577 mysql_free_result(result);
578 return row_count;
579 }
580
581
582 /* Process the statement result set */
583
584 #define MAX_RES_FIELDS 50
585 #define MAX_FIELD_DATA_SIZE 255
586
my_process_stmt_result(MYSQL_STMT * stmt)587 static int my_process_stmt_result(MYSQL_STMT *stmt)
588 {
589 int field_count;
590 int row_count= 0;
591 MYSQL_BIND buffer[MAX_RES_FIELDS];
592 MYSQL_FIELD *field;
593 MYSQL_RES *result;
594 char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE];
595 ulong length[MAX_RES_FIELDS];
596 my_bool is_null[MAX_RES_FIELDS];
597 int rc, i;
598
599 if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */
600 {
601 while (!mysql_stmt_fetch(stmt))
602 row_count++;
603 return row_count;
604 }
605
606 field_count= MY_MIN(mysql_num_fields(result), MAX_RES_FIELDS);
607
608 memset(buffer, 0, sizeof(buffer));
609 memset(length, 0, sizeof(length));
610 memset(is_null, 0, sizeof(is_null));
611
612 for(i= 0; i < field_count; i++)
613 {
614 buffer[i].buffer_type= MYSQL_TYPE_STRING;
615 buffer[i].buffer_length= MAX_FIELD_DATA_SIZE;
616 buffer[i].length= &length[i];
617 buffer[i].buffer= (void *) data[i];
618 buffer[i].is_null= &is_null[i];
619 }
620
621 rc= mysql_stmt_bind_result(stmt, buffer);
622 check_execute(stmt, rc);
623
624 rc= 1;
625 mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc);
626 rc= mysql_stmt_store_result(stmt);
627 check_execute(stmt, rc);
628 my_print_result_metadata(result);
629
630 mysql_field_seek(result, 0);
631 while ((rc= mysql_stmt_fetch(stmt)) == 0)
632 {
633 if (!opt_silent)
634 {
635 fputc('\t', stdout);
636 fputc('|', stdout);
637 }
638 mysql_field_seek(result, 0);
639 for (i= 0; i < field_count; i++)
640 {
641 field= mysql_fetch_field(result);
642 if (!opt_silent)
643 {
644 if (is_null[i])
645 fprintf(stdout, " %-*s |", (int) field->max_length, "NULL");
646 else if (length[i] == 0)
647 {
648 data[i][0]= '\0'; /* unmodified buffer */
649 fprintf(stdout, " %*s |", (int) field->max_length, data[i]);
650 }
651 else if (IS_NUM(field->type))
652 fprintf(stdout, " %*s |", (int) field->max_length, data[i]);
653 else
654 fprintf(stdout, " %-*s |", (int) field->max_length, data[i]);
655 }
656 }
657 if (!opt_silent)
658 {
659 fputc('\t', stdout);
660 fputc('\n', stdout);
661 }
662 row_count++;
663 }
664 DIE_UNLESS(rc == MYSQL_NO_DATA);
665 if (!opt_silent)
666 {
667 if (row_count)
668 my_print_dashes(result);
669 fprintf(stdout, "\n\t%d %s returned\n", row_count,
670 row_count == 1 ? "row" : "rows");
671 }
672 mysql_free_result(result);
673 return row_count;
674 }
675
676
677 /* Prepare statement, execute, and process result set for given query */
678
my_stmt_result(const char * buff)679 int my_stmt_result(const char *buff)
680 {
681 MYSQL_STMT *stmt;
682 int row_count;
683 int rc;
684
685 if (!opt_silent)
686 fprintf(stdout, "\n\n %s", buff);
687 stmt= mysql_simple_prepare(mysql, buff);
688 check_stmt(stmt);
689
690 rc= mysql_stmt_execute(stmt);
691 check_execute(stmt, rc);
692
693 row_count= my_process_stmt_result(stmt);
694 mysql_stmt_close(stmt);
695
696 return row_count;
697 }
698
699 /* Print the total number of warnings and the warnings themselves. */
700
my_process_warnings(MYSQL * conn,unsigned expected_warning_count)701 void my_process_warnings(MYSQL *conn, unsigned expected_warning_count)
702 {
703 MYSQL_RES *result;
704 int rc;
705
706 if (!opt_silent)
707 fprintf(stdout, "\n total warnings: %u (expected: %u)\n",
708 mysql_warning_count(conn), expected_warning_count);
709
710 DIE_UNLESS(mysql_warning_count(mysql) == expected_warning_count);
711
712 rc= mysql_query(conn, "SHOW WARNINGS");
713 DIE_UNLESS(rc == 0);
714
715 result= mysql_store_result(conn);
716 mytest(result);
717
718 rc= my_process_result_set(result);
719 mysql_free_result(result);
720 }
721
722
723 /* Utility function to verify a particular column data */
724
verify_col_data(const char * table,const char * col,const char * exp_data)725 static void verify_col_data(const char *table, const char *col,
726 const char *exp_data)
727 {
728 static char query[MAX_TEST_QUERY_LENGTH];
729 MYSQL_RES *result;
730 MYSQL_ROW row;
731 int rc, field= 1;
732
733 if (table && col)
734 {
735 strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS);
736 if (!opt_silent)
737 fprintf(stdout, "\n %s", query);
738 rc= mysql_query(mysql, query);
739 myquery(rc);
740
741 field= 0;
742 }
743
744 result= mysql_use_result(mysql);
745 mytest(result);
746
747 if (!(row= mysql_fetch_row(result)) || !row[field])
748 {
749 fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***");
750 exit(1);
751 }
752 if (strcmp(row[field], exp_data))
753 {
754 fprintf(stdout, "\n obtained: `%s` (expected: `%s`)",
755 row[field], exp_data);
756 DIE_UNLESS(FALSE);
757 }
758 mysql_free_result(result);
759 }
760
761
762 /* Utility function to verify the field members */
763
764 #define verify_prepare_field(result,no,name,org_name,type,table, \
765 org_table,db,length,def) \
766 do_verify_prepare_field((result),(no),(name),(org_name),(type), \
767 (table),(org_table),(db),(length),(def), \
768 __FILE__, __LINE__)
769
do_verify_prepare_field(MYSQL_RES * result,unsigned int no,const char * name,const char * org_name,enum enum_field_types type,const char * table,const char * org_table,const char * db,unsigned long length,const char * def,const char * file,int line)770 static void do_verify_prepare_field(MYSQL_RES *result,
771 unsigned int no, const char *name,
772 const char *org_name,
773 enum enum_field_types type,
774 const char *table,
775 const char *org_table, const char *db,
776 unsigned long length, const char *def,
777 const char *file, int line)
778 {
779 MYSQL_FIELD *field;
780 CHARSET_INFO *cs;
781 ulonglong expected_field_length;
782
783 if (!(field= mysql_fetch_field_direct(result, no)))
784 {
785 fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***");
786 exit(1);
787 }
788 cs= get_charset(field->charsetnr, 0);
789 DIE_UNLESS(cs);
790 if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32)
791 expected_field_length= UINT_MAX32;
792 if (!opt_silent)
793 {
794 fprintf(stdout, "\n field[%d]:", no);
795 fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name);
796 fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)",
797 field->org_name, org_name);
798 fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type);
799 if (table)
800 fprintf(stdout, "\n table :`%s`\t(expected: `%s`)",
801 field->table, table);
802 if (org_table)
803 fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)",
804 field->org_table, org_table);
805 fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db);
806 fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)",
807 field->length, expected_field_length);
808 fprintf(stdout, "\n maxlength:`%ld`", field->max_length);
809 fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr);
810 fprintf(stdout, "\n default :`%s`\t(expected: `%s`)",
811 field->def ? field->def : "(null)", def ? def: "(null)");
812 fprintf(stdout, "\n");
813 }
814 DIE_UNLESS(strcmp(field->name, name) == 0);
815 DIE_UNLESS(strcmp(field->org_name, org_name) == 0);
816 /*
817 XXX: silent column specification change works based on number of
818 bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even
819 for CHAR(2) column if its character set is multibyte.
820 VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would
821 expect.
822 */
823 if (cs->mbmaxlen == 1)
824 {
825 if (field->type != type)
826 {
827 fprintf(stderr,
828 "Expected field type: %d, got type: %d in file %s, line %d\n",
829 (int) type, (int) field->type, file, line);
830 DIE_UNLESS(field->type == type);
831 }
832 }
833 if (table)
834 DIE_UNLESS(strcmp(field->table, table) == 0);
835 if (org_table)
836 DIE_UNLESS(strcmp(field->org_table, org_table) == 0);
837 DIE_UNLESS(strcmp(field->db, db) == 0);
838 /*
839 Character set should be taken into account for multibyte encodings, such
840 as utf8. Field length is calculated as number of characters * maximum
841 number of bytes a character can occupy.
842 */
843 if (length && (field->length != expected_field_length))
844 {
845 fprintf(stderr, "Expected field length: %llu, got length: %lu\n",
846 expected_field_length, field->length);
847 DIE_UNLESS(field->length == expected_field_length);
848 }
849 if (def)
850 DIE_UNLESS(strcmp(field->def, def) == 0);
851 }
852
853
854 /* Utility function to verify the parameter count */
855
verify_param_count(MYSQL_STMT * stmt,long exp_count)856 static void verify_param_count(MYSQL_STMT *stmt, long exp_count)
857 {
858 long param_count= mysql_stmt_param_count(stmt);
859 if (!opt_silent)
860 fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)",
861 param_count, exp_count);
862 DIE_UNLESS(param_count == exp_count);
863 }
864
865
866 /* Utility function to verify the total affected rows */
867
verify_st_affected_rows(MYSQL_STMT * stmt,ulonglong exp_count)868 static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count)
869 {
870 ulonglong affected_rows= mysql_stmt_affected_rows(stmt);
871 if (!opt_silent)
872 fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
873 (long) affected_rows, (long) exp_count);
874 DIE_UNLESS(affected_rows == exp_count);
875 }
876
877
878 /* Utility function to verify the total affected rows */
879
verify_affected_rows(ulonglong exp_count)880 static void verify_affected_rows(ulonglong exp_count)
881 {
882 ulonglong affected_rows= mysql_affected_rows(mysql);
883 if (!opt_silent)
884 fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
885 (long) affected_rows, (long) exp_count);
886 DIE_UNLESS(affected_rows == exp_count);
887 }
888
889
890 /* Utility function to verify the total fields count */
891
verify_field_count(MYSQL_RES * result,uint exp_count)892 static void verify_field_count(MYSQL_RES *result, uint exp_count)
893 {
894 uint field_count= mysql_num_fields(result);
895 if (!opt_silent)
896 fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)",
897 field_count, exp_count);
898 DIE_UNLESS(field_count == exp_count);
899 }
900
901
902 /* Utility function to execute a query using prepare-execute */
903
904 #ifndef EMBEDDED_LIBRARY
execute_prepare_query(const char * query,ulonglong exp_count)905 static void execute_prepare_query(const char *query, ulonglong exp_count)
906 {
907 MYSQL_STMT *stmt;
908 ulonglong affected_rows;
909 int rc;
910
911 stmt= mysql_simple_prepare(mysql, query);
912 check_stmt(stmt);
913
914 rc= mysql_stmt_execute(stmt);
915 myquery(rc);
916
917 affected_rows= mysql_stmt_affected_rows(stmt);
918 if (!opt_silent)
919 fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
920 (long) affected_rows, (long) exp_count);
921
922 DIE_UNLESS(affected_rows == exp_count);
923 mysql_stmt_close(stmt);
924 }
925 #endif
926
927 /*
928 Accepts arbitrary number of queries and runs them against the database.
929 Used to fill tables for each test.
930 */
931
fill_tables(const char ** query_list,unsigned query_count)932 void fill_tables(const char **query_list, unsigned query_count)
933 {
934 int rc;
935 const char **query;
936 DBUG_ENTER("fill_tables");
937 for (query= query_list; query < query_list + query_count;
938 ++query)
939 {
940 rc= mysql_query(mysql, *query);
941 myquery(rc);
942 }
943 DBUG_VOID_RETURN;
944 }
945
946 /*
947 All state of fetch from one statement: statement handle, out buffers,
948 fetch position.
949 See fetch_n for for the only use case.
950 */
951
952 enum { MAX_COLUMN_LENGTH= 255 };
953
954 typedef struct st_stmt_fetch
955 {
956 const char *query;
957 unsigned stmt_no;
958 MYSQL_STMT *handle;
959 my_bool is_open;
960 MYSQL_BIND *bind_array;
961 char **out_data;
962 unsigned long *out_data_length;
963 unsigned column_count;
964 unsigned row_count;
965 } Stmt_fetch;
966
967
968 /*
969 Create statement handle, prepare it with statement, execute and allocate
970 fetch buffers.
971 */
972
stmt_fetch_init(Stmt_fetch * fetch,unsigned stmt_no_arg,const char * query_arg)973 void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg,
974 const char *query_arg)
975 {
976 unsigned long type= CURSOR_TYPE_READ_ONLY;
977 int rc;
978 unsigned i;
979 MYSQL_RES *metadata;
980 DBUG_ENTER("stmt_fetch_init");
981
982 /* Save query and statement number for error messages */
983 fetch->stmt_no= stmt_no_arg;
984 fetch->query= query_arg;
985
986 fetch->handle= mysql_stmt_init(mysql);
987
988 rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
989 check_execute(fetch->handle, rc);
990
991 /*
992 The attribute is sent to server on execute and asks to open read-only
993 for result set
994 */
995 mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
996 (const void*) &type);
997
998 rc= mysql_stmt_execute(fetch->handle);
999 check_execute(fetch->handle, rc);
1000
1001 /* Find out total number of columns in result set */
1002 metadata= mysql_stmt_result_metadata(fetch->handle);
1003 fetch->column_count= mysql_num_fields(metadata);
1004 mysql_free_result(metadata);
1005
1006 /*
1007 Now allocate bind handles and buffers for output data:
1008 calloc memory to reduce number of MYSQL_BIND members we need to
1009 set up.
1010 */
1011
1012 fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
1013 fetch->column_count);
1014 fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
1015 fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
1016 fetch->column_count);
1017 for (i= 0; i < fetch->column_count; ++i)
1018 {
1019 fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
1020 fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
1021 fetch->bind_array[i].buffer= fetch->out_data[i];
1022 fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
1023 fetch->bind_array[i].length= fetch->out_data_length + i;
1024 }
1025
1026 mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
1027
1028 fetch->row_count= 0;
1029 fetch->is_open= TRUE;
1030
1031 /* Ready for reading rows */
1032 DBUG_VOID_RETURN;
1033 }
1034
1035
1036 /* Fetch and print one row from cursor */
1037
stmt_fetch_fetch_row(Stmt_fetch * fetch)1038 int stmt_fetch_fetch_row(Stmt_fetch *fetch)
1039 {
1040 int rc;
1041 unsigned i;
1042 DBUG_ENTER("stmt_fetch_fetch_row");
1043
1044 if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
1045 {
1046 ++fetch->row_count;
1047 if (!opt_silent)
1048 printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count);
1049 for (i= 0; i < fetch->column_count; ++i)
1050 {
1051 fetch->out_data[i][fetch->out_data_length[i]]= '\0';
1052 if (!opt_silent)
1053 printf("column %d: %s\n", i+1, fetch->out_data[i]);
1054 }
1055 }
1056 else
1057 fetch->is_open= FALSE;
1058 DBUG_RETURN(rc);
1059 }
1060
1061
stmt_fetch_close(Stmt_fetch * fetch)1062 void stmt_fetch_close(Stmt_fetch *fetch)
1063 {
1064 unsigned i;
1065 DBUG_ENTER("stmt_fetch_close");
1066
1067 for (i= 0; i < fetch->column_count; ++i)
1068 free(fetch->out_data[i]);
1069 free(fetch->out_data);
1070 free(fetch->out_data_length);
1071 free(fetch->bind_array);
1072 mysql_stmt_close(fetch->handle);
1073 DBUG_VOID_RETURN;
1074 }
1075
1076 /*
1077 For given array of queries, open query_count cursors and fetch
1078 from them in simultaneous manner.
1079 In case there was an error in one of the cursors, continue
1080 reading from the rest.
1081 */
1082
1083 enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
1084
fetch_n(const char ** query_list,unsigned query_count,enum fetch_type fetch_type)1085 my_bool fetch_n(const char **query_list, unsigned query_count,
1086 enum fetch_type fetch_type)
1087 {
1088 unsigned open_statements= query_count;
1089 int rc, error_count= 0;
1090 Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
1091 query_count);
1092 Stmt_fetch *fetch;
1093 DBUG_ENTER("fetch_n");
1094
1095 for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
1096 {
1097 /* Init will exit(1) in case of error */
1098 stmt_fetch_init(fetch, fetch - fetch_array,
1099 query_list[fetch - fetch_array]);
1100 }
1101
1102 if (fetch_type == USE_STORE_RESULT)
1103 {
1104 for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
1105 {
1106 rc= mysql_stmt_store_result(fetch->handle);
1107 check_execute(fetch->handle, rc);
1108 }
1109 }
1110
1111 while (open_statements)
1112 {
1113 for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
1114 {
1115 if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
1116 {
1117 open_statements--;
1118 /*
1119 We try to fetch from the rest of the statements in case of
1120 error
1121 */
1122 if (rc != MYSQL_NO_DATA)
1123 {
1124 fprintf(stderr,
1125 "Got error reading rows from statement %d,\n"
1126 "query is: %s,\n"
1127 "error message: %s", (int) (fetch - fetch_array),
1128 fetch->query,
1129 mysql_stmt_error(fetch->handle));
1130 error_count++;
1131 }
1132 }
1133 }
1134 }
1135 if (error_count)
1136 fprintf(stderr, "Fetch FAILED");
1137 else
1138 {
1139 unsigned total_row_count= 0;
1140 for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
1141 total_row_count+= fetch->row_count;
1142 if (!opt_silent)
1143 printf("Success, total rows fetched: %d\n", total_row_count);
1144 }
1145 for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
1146 stmt_fetch_close(fetch);
1147 free(fetch_array);
1148 DBUG_RETURN(error_count != 0);
1149 }
1150
1151 /* Separate thread query to test some cases */
1152
thread_query(const char * query)1153 static my_bool thread_query(const char *query)
1154 {
1155 MYSQL *l_mysql;
1156 my_bool error;
1157
1158 error= 0;
1159 if (!opt_silent)
1160 fprintf(stdout, "\n in thread_query(%s)", query);
1161 if (!(l_mysql= mysql_client_init(NULL)))
1162 {
1163 myerror("mysql_client_init() failed");
1164 return 1;
1165 }
1166 if (!(mysql_real_connect(l_mysql, opt_host, opt_user,
1167 opt_password, current_db, opt_port,
1168 opt_unix_socket, 0)))
1169 {
1170 myerror("connection failed");
1171 error= 1;
1172 goto end;
1173 }
1174 l_mysql->reconnect= 1;
1175 if (mysql_query(l_mysql, query))
1176 {
1177 fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql));
1178 error= 1;
1179 goto end;
1180 }
1181 mysql_commit(l_mysql);
1182 end:
1183 mysql_close(l_mysql);
1184 return error;
1185 }
1186
1187
1188 static struct my_option client_test_long_options[] =
1189 {
1190 {"basedir", 'b', "Basedir for tests.", &opt_basedir,
1191 &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1192 {"count", 't', "Number of times test to be executed", &opt_count_read,
1193 &opt_count_read, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
1194 {"database", 'D', "Database to use", &opt_db, &opt_db,
1195 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1196 {"do-not-drop-database", 'd', "Do not drop database while disconnecting",
1197 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1198 {"debug", '#', "Output debug log", &default_dbug_option,
1199 &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1200 {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
1201 0, 0, 0, 0, 0},
1202 {"host", 'h', "Connect to host", &opt_host, &opt_host,
1203 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1204 {"password", 'p',
1205 "Password to use when connecting to server. If password is not given it's asked from the tty.",
1206 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1207 {"port", 'P', "Port number to use for connection or 0 for default to, in "
1208 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
1209 #if MYSQL_PORT_DEFAULT == 0
1210 "/etc/services, "
1211 #endif
1212 "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
1213 &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1214 {"server-arg", 'A', "Send embedded server this as a parameter.",
1215 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1216 {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG,
1217 0, 0, 0, 0, 0, 0},
1218 {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0,
1219 0},
1220 #ifdef HAVE_SMEM
1221 {"shared-memory-base-name", 'm', "Base name of shared memory.",
1222 &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0,
1223 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1224 #endif
1225 {"socket", 'S', "Socket file to use for connection",
1226 &opt_unix_socket, &opt_unix_socket, 0, GET_STR,
1227 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1228 {"testcase", 'c',
1229 "May disable some code when runs as mysql-test-run testcase.",
1230 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
1231 #ifndef DONT_ALLOW_USER_CHANGE
1232 {"user", 'u', "User for login if not current user", &opt_user,
1233 &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1234 #endif
1235 {"vardir", 'v', "Data dir for tests.", &opt_vardir,
1236 &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1237 {"getopt-ll-test", 'g', "Option for testing bug in getopt library",
1238 &opt_getopt_ll_test, &opt_getopt_ll_test, 0,
1239 GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0},
1240 {"plugin_dir", 0, "Directory for client-side plugins.",
1241 &opt_plugin_dir, &opt_plugin_dir, 0,
1242 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1243 {"default_auth", 0, "Default authentication client-side plugin to use.",
1244 &opt_default_auth, &opt_default_auth, 0,
1245 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1246 {"secure-auth", 0, "Refuse client connecting to server if it"
1247 " uses old (pre-4.1.1) protocol.", &opt_secure_auth,
1248 &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1249 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1250 };
1251
1252
usage(void)1253 static void usage(void)
1254 {
1255 /* show the usage string when the user asks for this */
1256 putc('\n', stdout);
1257 printf("%s Ver %s Distrib %s, for %s (%s)\n",
1258 my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
1259 puts("By Monty, Venu, Kent and others\n");
1260 printf("\
1261 Copyright (C) 2002-2004 MySQL AB\n\
1262 This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
1263 and you are welcome to modify and redistribute it under the GPL license\n");
1264 printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname);
1265 my_print_help(client_test_long_options);
1266 print_defaults("my", client_test_load_default_groups);
1267 my_print_variables(client_test_long_options);
1268 }
1269
1270 static struct my_tests_st *get_my_tests(); /* To be defined in main .c file */
1271
1272 static struct my_tests_st *my_testlist= 0;
1273
1274 static my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)1275 get_one_option(int optid, const struct my_option *opt MY_ATTRIBUTE((unused)),
1276 char *argument)
1277 {
1278 switch (optid) {
1279 case '#':
1280 DBUG_PUSH(argument ? argument : default_dbug_option);
1281 break;
1282 case 'c':
1283 opt_testcase = 1;
1284 break;
1285 case 'p':
1286 if (argument)
1287 {
1288 char *start=argument;
1289 my_free(opt_password);
1290 opt_password= my_strdup(argument, MYF(MY_FAE));
1291 while (*argument) *argument++= 'x'; /* Destroy argument */
1292 if (*start)
1293 start[1]=0;
1294 }
1295 else
1296 tty_password= 1;
1297 break;
1298 case 's':
1299 if (argument == disabled_my_option)
1300 opt_silent= 0;
1301 else
1302 opt_silent++;
1303 break;
1304 case 'd':
1305 opt_drop_db= 0;
1306 break;
1307 case 'A':
1308 /*
1309 When the embedded server is being tested, the test suite needs to be
1310 able to pass command-line arguments to the embedded server so it can
1311 locate the language files and data directory. The test suite
1312 (mysql-test-run) never uses config files, just command-line options.
1313 */
1314 if (!embedded_server_arg_count)
1315 {
1316 embedded_server_arg_count= 1;
1317 embedded_server_args[0]= (char*) "";
1318 }
1319 if (embedded_server_arg_count == MAX_SERVER_ARGS-1 ||
1320 !(embedded_server_args[embedded_server_arg_count++]=
1321 my_strdup(argument, MYF(MY_FAE))))
1322 {
1323 DIE("Can't use server argument");
1324 }
1325 break;
1326 case 'T':
1327 {
1328 struct my_tests_st *fptr;
1329
1330 printf("All possible test names:\n\n");
1331 for (fptr= my_testlist; fptr->name; fptr++)
1332 printf("%s\n", fptr->name);
1333 exit(0);
1334 break;
1335 }
1336 case '?':
1337 case 'I': /* Info */
1338 usage();
1339 exit(0);
1340 break;
1341 }
1342 return 0;
1343 }
1344
get_options(int * argc,char *** argv)1345 static void get_options(int *argc, char ***argv)
1346 {
1347 int ho_error;
1348
1349 /* Copy argv from load_defaults, so we can free it when done. */
1350 defaults_argv= *argv;
1351 /* reset --silent option */
1352 opt_silent= 0;
1353
1354 if ((ho_error= handle_options(argc, argv, client_test_long_options,
1355 get_one_option)))
1356 exit(ho_error);
1357
1358 if (tty_password)
1359 opt_password= get_tty_password(NullS);
1360 return;
1361 }
1362
1363 /*
1364 Print the test output on successful execution before exiting
1365 */
1366
print_test_output()1367 static void print_test_output()
1368 {
1369 if (opt_silent < 3)
1370 {
1371 fprintf(stdout, "\n\n");
1372 fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)",
1373 test_count-1, opt_count);
1374 if (!opt_silent)
1375 {
1376 fprintf(stdout, "\n Total execution time: %g SECS", total_time);
1377 if (opt_count > 1)
1378 fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count);
1379 }
1380
1381 fprintf(stdout, "\n\n!!! SUCCESS !!!\n");
1382 }
1383 }
1384
1385 /***************************************************************************
1386 main routine
1387 ***************************************************************************/
1388
1389
main(int argc,char ** argv)1390 int main(int argc, char **argv)
1391 {
1392 int i;
1393 char **tests_to_run= NULL, **curr_test;
1394 struct my_tests_st *fptr;
1395 my_testlist= get_my_tests();
1396
1397 MY_INIT(argv[0]);
1398
1399 /* Copy the original arguments, so it can be reused for restarting. */
1400 original_argc= argc;
1401 original_argv= malloc(argc * sizeof(char*));
1402 if (argc && !original_argv)
1403 exit(1);
1404 for (i= 0; i < argc; i++)
1405 original_argv[i]= strdup(argv[i]);
1406
1407 if (load_defaults("my", client_test_load_default_groups, &argc, &argv))
1408 exit(1);
1409
1410 get_options(&argc, &argv);
1411
1412 /* Set main opt_count. */
1413 opt_count= opt_count_read;
1414
1415 /* If there are any arguments left (named tests), save them. */
1416 if (argc)
1417 {
1418 tests_to_run= malloc((argc + 1) * sizeof(char*));
1419 if (!tests_to_run)
1420 exit(1);
1421 for (i= 0; i < argc; i++)
1422 tests_to_run[i]= strdup(argv[i]);
1423 tests_to_run[i]= NULL;
1424 }
1425
1426 if (mysql_server_init(embedded_server_arg_count,
1427 embedded_server_args,
1428 (char**) embedded_server_groups))
1429 DIE("Can't initialize MySQL server");
1430
1431 /* connect to server with no flags, default protocol, auto reconnect true */
1432 mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1);
1433
1434 total_time= 0;
1435 for (iter_count= 1; iter_count <= opt_count; iter_count++)
1436 {
1437 /* Start of tests */
1438 test_count= 1;
1439 start_time= time((time_t *)0);
1440 if (!tests_to_run)
1441 {
1442 for (fptr= my_testlist; fptr->name; fptr++)
1443 (*fptr->function)();
1444 }
1445 else
1446 {
1447 for (curr_test= tests_to_run ; *curr_test ; curr_test++)
1448 {
1449 for (fptr= my_testlist; fptr->name; fptr++)
1450 {
1451 if (!strcmp(fptr->name, *curr_test))
1452 {
1453 (*fptr->function)();
1454 break;
1455 }
1456 }
1457 if (!fptr->name)
1458 {
1459 fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv);
1460 fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n",
1461 my_progname);
1462 client_disconnect(mysql);
1463 free_defaults(defaults_argv);
1464 mysql_server_end();
1465 exit(1);
1466 }
1467 }
1468 }
1469
1470 end_time= time((time_t *)0);
1471 total_time+= difftime(end_time, start_time);
1472
1473 /* End of tests */
1474 }
1475
1476 client_disconnect(mysql); /* disconnect from server */
1477
1478 free_defaults(defaults_argv);
1479 print_test_output();
1480
1481 while (embedded_server_arg_count > 1)
1482 my_free(embedded_server_args[--embedded_server_arg_count]);
1483
1484 mysql_server_end();
1485
1486 my_end(0);
1487
1488 for (i= 0; i < original_argc; i++)
1489 free(original_argv[i]);
1490 if (original_argc)
1491 free(original_argv);
1492 if (tests_to_run)
1493 {
1494 for (curr_test= tests_to_run ; *curr_test ; curr_test++)
1495 free(*curr_test);
1496 free(tests_to_run);
1497 }
1498 my_free(opt_password);
1499 my_free(opt_host);
1500 exit(0);
1501 }
1502