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