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