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-1335  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>
35 static 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 */
47 static int   opt_testcase __attribute__((unused)) = 0;
48 static char *opt_db= 0;
49 static char *opt_user= 0;
50 static char *opt_password= 0;
51 static char *opt_host= 0;
52 static char *opt_unix_socket= 0;
53 #ifdef HAVE_SMEM
54 static char *shared_memory_base_name= 0;
55 #endif
56 static unsigned int  opt_port;
57 static my_bool tty_password= 0, opt_silent= 0;
58 
59 static MYSQL *mysql= 0;
60 static char current_db[]= "client_test_db";
61 static unsigned int test_count= 0;
62 static unsigned int opt_count= 0;
63 static unsigned int opt_count_read= 0;
64 static unsigned int iter_count= 0;
65 static my_bool have_innodb= FALSE;
66 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
67 static unsigned int opt_drop_db= 1;
68 
69 static const char *opt_basedir= "./";
70 static const char *opt_vardir= "mysql-test/var";
71 static char mysql_charsets_dir[FN_REFLEN+1];
72 
73 static longlong opt_getopt_ll_test= 0;
74 
75 static char **defaults_argv;
76 static int   original_argc;
77 static char **original_argv;
78 static int embedded_server_arg_count= 0;
79 static char *embedded_server_args[MAX_SERVER_ARGS];
80 
81 static const char *embedded_server_groups[]= {
82   "server",
83   "embedded",
84   "mysql_client_test_SERVER",
85   NullS
86 };
87 
88 static time_t start_time, end_time;
89 static double total_time;
90 
91 const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace";
92 
93 struct my_tests_st
94 {
95   const char *name;
96   void       (*function)();
97 };
98 
99 #define myheader(str)							\
100 DBUG_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)							\
110 DBUG_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 
118 static void print_error(const char *msg);
119 static void print_st_error(MYSQL_STMT *stmt, const char *msg);
120 static void client_disconnect(MYSQL* mysql);
121 static 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 
142 static 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 
204 static int cmp_double(double *a, double *b)
205 {
206   return *a == *b;
207 }
208 
209 
210 /* Print the error message */
211 
212 static 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 
230 static 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 */
253 static 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 
278 static 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 
307 static MYSQL_STMT *STDCALL
308 mysql_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 */
331 static 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 
401 static 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 
431 static 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 
453 static 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 
501 static 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 
557 static 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 
577 static 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 
669 int 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 
691 void 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 
715 static 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 
760 static 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 
848 static 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 
860 static 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 
872 static 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 
884 static 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
897 static 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 /*
920 Accepts arbitrary number of queries and runs them against the database.
921 Used to fill tables for each test.
922 */
923 
924 void 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 /*
939 All state of fetch from one statement: statement handle, out buffers,
940 fetch position.
941 See fetch_n for for the only use case.
942 */
943 
944 enum { MAX_COLUMN_LENGTH= 255 };
945 
946 typedef struct st_stmt_fetch
947 {
948 const char *query;
949 unsigned stmt_no;
950 MYSQL_STMT *handle;
951 my_bool is_open;
952 MYSQL_BIND *bind_array;
953 char **out_data;
954 unsigned long *out_data_length;
955 unsigned column_count;
956 unsigned row_count;
957 } Stmt_fetch;
958 
959 
960 /*
961 Create statement handle, prepare it with statement, execute and allocate
962 fetch buffers.
963 */
964 
965 void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg,
966 const 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 
1030 int 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 
1054 void 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 /*
1069 For given array of queries, open query_count cursors and fetch
1070 from them in simultaneous manner.
1071 In case there was an error in one of the cursors, continue
1072 reading from the rest.
1073 */
1074 
1075 enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
1076 
1077 my_bool fetch_n(const char **query_list, unsigned query_count,
1078 enum 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 
1145 static 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 
1180 static 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 
1193 static const char *client_test_load_default_groups[]=
1194 { "client", "client-server", "client-mariadb", 0 };
1195 static char **defaults_argv;
1196 
1197 static 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 
1266 static 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("\
1274 Copyright (C) 2002-2004 MySQL AB\n\
1275 This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
1276 and 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 
1283 static struct my_tests_st *get_my_tests();  /* To be defined in main .c file */
1284 
1285 static struct my_tests_st *my_testlist= 0;
1286 
1287 static my_bool
1288 get_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 
1362 static 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 
1383 static 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 
1406 int 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