MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysqlslap.c
1 /*
2  Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights 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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  MySQL Slap
20 
21  A simple program designed to work as if multiple clients querying the database,
22  then reporting the timing of each stage.
23 
24  MySQL slap runs three stages:
25  1) Create schema,table, and optionally any SP or data you want to beign
26  the test with. (single client)
27  2) Load test (many clients)
28  3) Cleanup (disconnection, drop table if specified, single client)
29 
30  Examples:
31 
32  Supply your own create and query SQL statements, with 50 clients
33  querying (200 selects for each):
34 
35  mysqlslap --delimiter=";" \
36  --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
37  --query="SELECT * FROM A" --concurrency=50 --iterations=200
38 
39  Let the program build the query SQL statement with a table of two int
40  columns, three varchar columns, five clients querying (20 times each),
41  don't create the table or insert the data (using the previous test's
42  schema and data):
43 
44  mysqlslap --concurrency=5 --iterations=20 \
45  --number-int-cols=2 --number-char-cols=3 \
46  --auto-generate-sql
47 
48  Tell the program to load the create, insert and query SQL statements from
49  the specified files, where the create.sql file has multiple table creation
50  statements delimited by ';' and multiple insert statements delimited by ';'.
51  The --query file will have multiple queries delimited by ';', run all the
52  load statements, and then run all the queries in the query file
53  with five clients (five times each):
54 
55  mysqlslap --concurrency=5 \
56  --iterations=5 --query=query.sql --create=create.sql \
57  --delimiter=";"
58 
59 TODO:
60  Add language for better tests
61  String length for files and those put on the command line are not
62  setup to handle binary data.
63  More stats
64  Break up tests and run them on multiple hosts at once.
65  Allow output to be fed into a database directly.
66 
67 */
68 
69 #define SLAP_VERSION "1.0"
70 
71 #define HUGE_STRING_LENGTH 8196
72 #define RAND_STRING_SIZE 126
73 
74 /* Types */
75 #define SELECT_TYPE 0
76 #define UPDATE_TYPE 1
77 #define INSERT_TYPE 2
78 #define UPDATE_TYPE_REQUIRES_PREFIX 3
79 #define CREATE_TABLE_TYPE 4
80 #define SELECT_TYPE_REQUIRES_PREFIX 5
81 #define DELETE_TYPE_REQUIRES_PREFIX 6
82 
83 #include "client_priv.h"
84 #include "my_default.h"
85 #include <mysqld_error.h>
86 #include <my_dir.h>
87 #include <signal.h>
88 #include <stdarg.h>
89 #include <sslopt-vars.h>
90 #include <sys/types.h>
91 #ifndef __WIN__
92 #include <sys/wait.h>
93 #endif
94 #include <ctype.h>
95 #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
96 
97 #ifdef __WIN__
98 #define srandom srand
99 #define random rand
100 #define snprintf _snprintf
101 #endif
102 
103 #ifdef HAVE_SMEM
104 static char *shared_memory_base_name=0;
105 #endif
106 
107 /* Global Thread counter */
108 uint thread_counter;
109 pthread_mutex_t counter_mutex;
110 pthread_cond_t count_threshhold;
111 uint master_wakeup;
112 pthread_mutex_t sleeper_mutex;
113 pthread_cond_t sleep_threshhold;
114 
115 static char **defaults_argv;
116 
117 char **primary_keys;
118 unsigned long long primary_keys_number_of;
119 
120 static char *host= NULL, *opt_password= NULL, *user= NULL,
121  *user_supplied_query= NULL,
122  *user_supplied_pre_statements= NULL,
123  *user_supplied_post_statements= NULL,
124  *default_engine= NULL,
125  *pre_system= NULL,
126  *post_system= NULL,
127  *opt_mysql_unix_port= NULL;
128 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
129 static uint opt_enable_cleartext_plugin= 0;
130 static my_bool using_opt_enable_cleartext_plugin= 0;
131 
132 const char *delimiter= "\n";
133 
134 const char *create_schema_string= "mysqlslap";
135 
136 static my_bool opt_preserve= TRUE, opt_no_drop= FALSE;
137 static my_bool debug_info_flag= 0, debug_check_flag= 0;
138 static my_bool opt_only_print= FALSE;
139 static my_bool opt_compress= FALSE, tty_password= FALSE,
140  opt_silent= FALSE,
141  auto_generate_sql_autoincrement= FALSE,
142  auto_generate_sql_guid_primary= FALSE,
143  auto_generate_sql= FALSE;
144 const char *auto_generate_sql_type= "mixed";
145 
146 static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
147  CLIENT_MULTI_STATEMENTS |
148  CLIENT_REMEMBER_OPTIONS;
149 
150 
151 static int verbose, delimiter_length;
152 static uint commit_rate;
153 static uint detach_rate;
154 const char *num_int_cols_opt;
155 const char *num_char_cols_opt;
156 
157 /* Yes, we do set defaults here */
158 static unsigned int num_int_cols= 1;
159 static unsigned int num_char_cols= 1;
160 static unsigned int num_int_cols_index= 0;
161 static unsigned int num_char_cols_index= 0;
162 static unsigned int iterations;
163 static uint my_end_arg= 0;
164 static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
165 static ulonglong actual_queries= 0;
166 static ulonglong auto_actual_queries;
167 static ulonglong auto_generate_sql_unique_write_number;
168 static ulonglong auto_generate_sql_unique_query_number;
169 static unsigned int auto_generate_sql_secondary_indexes;
170 static ulonglong num_of_query;
171 static ulonglong auto_generate_sql_number;
172 const char *concurrency_str= NULL;
173 static char *create_string;
174 uint *concurrency;
175 
176 const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
177 const char *opt_csv_str;
178 File csv_file;
179 
180 static uint opt_protocol= 0;
181 
182 static int get_options(int *argc,char ***argv);
183 static uint opt_mysql_port= 0;
184 
185 static const char *load_default_groups[]= { "mysqlslap","client",0 };
186 
187 typedef struct statement statement;
188 
189 struct statement {
190  char *string;
191  size_t length;
192  unsigned char type;
193  char *option;
194  size_t option_length;
195  statement *next;
196 };
197 
198 typedef struct option_string option_string;
199 
201  char *string;
202  size_t length;
203  char *option;
204  size_t option_length;
205  option_string *next;
206 };
207 
208 typedef struct stats stats;
209 
210 struct stats {
211  long int timing;
212  uint users;
213  unsigned long long rows;
214 };
215 
216 typedef struct thread_context thread_context;
217 
219  statement *stmt;
220  ulonglong limit;
221 };
222 
223 typedef struct conclusions conclusions;
224 
225 struct conclusions {
226  char *engine;
227  long int avg_timing;
228  long int max_timing;
229  long int min_timing;
230  uint users;
231  unsigned long long avg_rows;
232  /* The following are not used yet */
233  unsigned long long max_rows;
234  unsigned long long min_rows;
235 };
236 
237 static option_string *engine_options= NULL;
238 static statement *pre_statements= NULL;
239 static statement *post_statements= NULL;
240 static statement *create_statements= NULL,
241  *query_statements= NULL;
242 
243 /* Prototypes */
244 void print_conclusions(conclusions *con);
245 void print_conclusions_csv(conclusions *con);
246 void generate_stats(conclusions *con, option_string *eng, stats *sptr);
247 uint parse_comma(const char *string, uint **range);
248 uint parse_delimiter(const char *script, statement **stmt, char delm);
249 uint parse_option(const char *origin, option_string **stmt, char delm);
250 static int drop_schema(MYSQL *mysql, const char *db);
251 uint get_random_string(char *buf);
252 static statement *build_table_string(void);
253 static statement *build_insert_string(void);
254 static statement *build_update_string(void);
255 static statement * build_select_string(my_bool key);
256 static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt);
257 static int drop_primary_key_list(void);
258 static int create_schema(MYSQL *mysql, const char *db, statement *stmt,
259  option_string *engine_stmt);
260 static int run_scheduler(stats *sptr, statement *stmts, uint concur,
261  ulonglong limit);
262 pthread_handler_t run_task(void *p);
263 void statement_cleanup(statement *stmt);
264 void option_cleanup(option_string *stmt);
265 void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr);
266 static int run_statements(MYSQL *mysql, statement *stmt);
267 int slap_connect(MYSQL *mysql);
268 static int run_query(MYSQL *mysql, const char *query, int len);
269 
270 static const char ALPHANUMERICS[]=
271  "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
272 
273 #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
274 
275 
276 static long int timedif(struct timeval a, struct timeval b)
277 {
278  register int us, s;
279 
280  us = a.tv_usec - b.tv_usec;
281  us /= 1000;
282  s = a.tv_sec - b.tv_sec;
283  s *= 1000;
284  return s + us;
285 }
286 
287 #ifdef __WIN__
288 static int gettimeofday(struct timeval *tp, void *tzp)
289 {
290  unsigned int ticks;
291  ticks= GetTickCount();
292  tp->tv_usec= ticks*1000;
293  tp->tv_sec= ticks/1000;
294 
295  return 0;
296 }
297 #endif
298 
299 int main(int argc, char **argv)
300 {
301  MYSQL mysql;
302  option_string *eptr;
303 
304  MY_INIT(argv[0]);
305 
306  my_getopt_use_args_separator= TRUE;
307  if (load_defaults("my",load_default_groups,&argc,&argv))
308  {
309  my_end(0);
310  exit(1);
311  }
312  my_getopt_use_args_separator= FALSE;
313  defaults_argv=argv;
314  if (get_options(&argc,&argv))
315  {
316  free_defaults(defaults_argv);
317  my_end(0);
318  exit(1);
319  }
320 
321  /* Seed the random number generator if we will be using it. */
322  if (auto_generate_sql)
323  srandom((uint)time(NULL));
324 
325  /* globals? Yes, so we only have to run strlen once */
326  delimiter_length= strlen(delimiter);
327 
328  if (argc > 2)
329  {
330  fprintf(stderr,"%s: Too many arguments\n",my_progname);
331  free_defaults(defaults_argv);
332  my_end(0);
333  exit(1);
334  }
335  mysql_init(&mysql);
336  if (opt_compress)
337  mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
338 #ifdef HAVE_OPENSSL
339  if (opt_use_ssl)
340  {
341  mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
342  opt_ssl_capath, opt_ssl_cipher);
343  mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
344  mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
345  }
346 #endif
347  if (opt_protocol)
348  mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
349 #ifdef HAVE_SMEM
350  if (shared_memory_base_name)
351  mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
352 #endif
353  mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
354 
355  if (opt_plugin_dir && *opt_plugin_dir)
356  mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
357 
358  if (opt_default_auth && *opt_default_auth)
359  mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
360 
361  mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
362  mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
363  "program_name", "mysqlslap");
364  if (using_opt_enable_cleartext_plugin)
365  mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
366  (char*) &opt_enable_cleartext_plugin);
367  if (!opt_only_print)
368  {
369  if (!(mysql_real_connect(&mysql, host, user, opt_password,
370  NULL, opt_mysql_port,
371  opt_mysql_unix_port, connect_flags)))
372  {
373  fprintf(stderr,"%s: Error when connecting to server: %s\n",
374  my_progname,mysql_error(&mysql));
375  free_defaults(defaults_argv);
376  my_end(0);
377  exit(1);
378  }
379  }
380 
381  pthread_mutex_init(&counter_mutex, NULL);
382  pthread_cond_init(&count_threshhold, NULL);
383  pthread_mutex_init(&sleeper_mutex, NULL);
384  pthread_cond_init(&sleep_threshhold, NULL);
385 
386  /* Main iterations loop */
387  eptr= engine_options;
388  do
389  {
390  /* For the final stage we run whatever queries we were asked to run */
391  uint *current;
392 
393  if (verbose >= 2)
394  printf("Starting Concurrency Test\n");
395 
396  if (*concurrency)
397  {
398  for (current= concurrency; current && *current; current++)
399  concurrency_loop(&mysql, *current, eptr);
400  }
401  else
402  {
403  uint infinite= 1;
404  do {
405  concurrency_loop(&mysql, infinite, eptr);
406  }
407  while (infinite++);
408  }
409 
410  if (!opt_preserve)
411  drop_schema(&mysql, create_schema_string);
412 
413  } while (eptr ? (eptr= eptr->next) : 0);
414 
415  pthread_mutex_destroy(&counter_mutex);
416  pthread_cond_destroy(&count_threshhold);
417  pthread_mutex_destroy(&sleeper_mutex);
418  pthread_cond_destroy(&sleep_threshhold);
419 
420  if (!opt_only_print)
421  mysql_close(&mysql); /* Close & free connection */
422 
423  /* now free all the strings we created */
424  my_free(opt_password);
425  my_free(concurrency);
426 
427  statement_cleanup(create_statements);
428  statement_cleanup(query_statements);
429  statement_cleanup(pre_statements);
430  statement_cleanup(post_statements);
431  option_cleanup(engine_options);
432 
433 #ifdef HAVE_SMEM
434  my_free(shared_memory_base_name);
435 #endif
436  free_defaults(defaults_argv);
437  my_end(my_end_arg);
438 
439  return 0;
440 }
441 
442 void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
443 {
444  unsigned int x;
445  stats *head_sptr;
446  stats *sptr;
447  conclusions conclusion;
448  unsigned long long client_limit;
449  int sysret;
450 
451  head_sptr= (stats *)my_malloc(sizeof(stats) * iterations,
452  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
453 
454  memset(&conclusion, 0, sizeof(conclusions));
455 
456  if (auto_actual_queries)
457  client_limit= auto_actual_queries;
458  else if (num_of_query)
459  client_limit= num_of_query / current;
460  else
461  client_limit= actual_queries;
462 
463  for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
464  {
465  /*
466  We might not want to load any data, such as when we are calling
467  a stored_procedure that doesn't use data, or we know we already have
468  data in the table.
469  */
470  if (!opt_preserve)
471  drop_schema(mysql, create_schema_string);
472 
473  /* First we create */
474  if (create_statements)
475  create_schema(mysql, create_schema_string, create_statements, eptr);
476 
477  /*
478  If we generated GUID we need to build a list of them from creation that
479  we can later use.
480  */
481  if (verbose >= 2)
482  printf("Generating primary key list\n");
483  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
484  generate_primary_key_list(mysql, eptr);
485 
486  if (commit_rate)
487  run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
488 
489  if (pre_system)
490  if ((sysret= system(pre_system)) != 0)
491  fprintf(stderr, "Warning: Execution of pre_system option returned %d.\n",
492  sysret);
493 
494  /*
495  Pre statements are always run after all other logic so they can
496  correct/adjust any item that they want.
497  */
498  if (pre_statements)
499  run_statements(mysql, pre_statements);
500 
501  run_scheduler(sptr, query_statements, current, client_limit);
502 
503  if (post_statements)
504  run_statements(mysql, post_statements);
505 
506  if (post_system)
507  if ((sysret= system(post_system)) != 0)
508  fprintf(stderr, "Warning: Execution of post_system option returned %d.\n",
509  sysret);
510 
511  /* We are finished with this run */
512  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
513  drop_primary_key_list();
514  }
515 
516  if (verbose >= 2)
517  printf("Generating stats\n");
518 
519  generate_stats(&conclusion, eptr, head_sptr);
520 
521  if (!opt_silent)
522  print_conclusions(&conclusion);
523  if (opt_csv_str)
524  print_conclusions_csv(&conclusion);
525 
526  my_free(head_sptr);
527 
528 }
529 
530 
531 static struct my_option my_long_options[] =
532 {
533  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
534  0, 0, 0, 0, 0, 0},
535  {"auto-generate-sql", 'a',
536  "Generate SQL where not supplied by file or command line.",
537  &auto_generate_sql, &auto_generate_sql,
538  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
539  {"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
540  "Add an AUTO_INCREMENT column to auto-generated tables.",
541  &auto_generate_sql_autoincrement,
542  &auto_generate_sql_autoincrement,
543  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
544  {"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
545  "Set this number to generate a set number of queries to run.",
546  &auto_actual_queries, &auto_actual_queries,
547  0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
548  {"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
549  "Add GUID based primary keys to auto-generated tables.",
550  &auto_generate_sql_guid_primary,
551  &auto_generate_sql_guid_primary,
552  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
553  {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
554  "Specify test load type: mixed, update, write, key, or read; default is mixed.",
555  &auto_generate_sql_type, &auto_generate_sql_type,
556  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
557  {"auto-generate-sql-secondary-indexes",
558  OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
559  "Number of secondary indexes to add to auto-generated tables.",
560  &auto_generate_sql_secondary_indexes,
561  &auto_generate_sql_secondary_indexes, 0,
562  GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
563  {"auto-generate-sql-unique-query-number",
564  OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
565  "Number of unique queries to generate for automatic tests.",
566  &auto_generate_sql_unique_query_number,
567  &auto_generate_sql_unique_query_number,
568  0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
569  {"auto-generate-sql-unique-write-number",
570  OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
571  "Number of unique queries to generate for auto-generate-sql-write-number.",
572  &auto_generate_sql_unique_write_number,
573  &auto_generate_sql_unique_write_number,
574  0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
575  {"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
576  "Number of row inserts to perform for each thread (default is 100).",
577  &auto_generate_sql_number, &auto_generate_sql_number,
578  0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
579  {"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
580  &commit_rate, &commit_rate, 0, GET_UINT, REQUIRED_ARG,
581  0, 0, 0, 0, 0, 0},
582  {"compress", 'C', "Use compression in server/client protocol.",
583  &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
584  0, 0, 0},
585  {"concurrency", 'c', "Number of clients to simulate for query to run.",
586  &concurrency_str, &concurrency_str, 0, GET_STR,
587  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
588  {"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
589  &create_string, &create_string, 0, GET_STR, REQUIRED_ARG,
590  0, 0, 0, 0, 0, 0},
591  {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
592  &create_schema_string, &create_schema_string, 0, GET_STR,
593  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
594  {"csv", OPT_SLAP_CSV,
595  "Generate CSV output to named file or to stdout if no file is named.",
596  NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
597 #ifdef DBUG_OFF
598  {"debug", '#', "This is a non-debug version. Catch this and exit.",
599  0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
600 #else
601  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
602  &default_dbug_option, &default_dbug_option, 0, GET_STR,
603  OPT_ARG, 0, 0, 0, 0, 0, 0},
604 #endif
605  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
606  &debug_check_flag, &debug_check_flag, 0,
607  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
608  {"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag,
609  &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
610  {"default_auth", OPT_DEFAULT_AUTH,
611  "Default authentication client-side plugin to use.",
612  &opt_default_auth, &opt_default_auth, 0,
613  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
614  {"delimiter", 'F',
615  "Delimiter to use in SQL statements supplied in file or command line.",
616  &delimiter, &delimiter, 0, GET_STR, REQUIRED_ARG,
617  0, 0, 0, 0, 0, 0},
618  {"detach", OPT_SLAP_DETACH,
619  "Detach (close and reopen) connections after X number of requests.",
620  &detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG,
621  0, 0, 0, 0, 0, 0},
622  {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
623  "Enable/disable the clear text authentication plugin.",
624  &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
625  0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
626  {"engine", 'e', "Storage engine to use for creating the table.",
628  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
629  {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR,
630  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
631  {"iterations", 'i', "Number of times to run the tests.", &iterations,
632  &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
633  {"no-drop", OPT_SLAP_NO_DROP, "Do not drop the schema after the test.",
634  &opt_no_drop, &opt_no_drop, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
635  {"number-char-cols", 'x',
636  "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
637  &num_char_cols_opt, &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
638  0, 0, 0, 0, 0, 0},
639  {"number-int-cols", 'y',
640  "Number of INT columns to create in table if specifying --auto-generate-sql.",
641  &num_int_cols_opt, &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
642  0, 0, 0, 0, 0, 0},
643  {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
644  "Limit each client to this number of queries (this is not exact).",
645  &num_of_query, &num_of_query, 0,
646  GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
647  {"only-print", OPT_MYSQL_ONLY_PRINT,
648  "Do not connect to the databases, but instead print out what would have "
649  "been done.",
650  &opt_only_print, &opt_only_print, 0, GET_BOOL, NO_ARG,
651  0, 0, 0, 0, 0, 0},
652  {"password", 'p',
653  "Password to use when connecting to server. If password is not given it's "
654  "asked from the tty.", 0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
655 #ifdef __WIN__
656  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
657  NO_ARG, 0, 0, 0, 0, 0, 0},
658 #endif
659  {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
660  &opt_plugin_dir, &opt_plugin_dir, 0,
661  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
662  {"port", 'P', "Port number to use for connection.", &opt_mysql_port,
663  &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
664  0},
665  {"post-query", OPT_SLAP_POST_QUERY,
666  "Query to run or file containing query to execute after tests have completed.",
667  &user_supplied_post_statements, &user_supplied_post_statements,
668  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
669  {"post-system", OPT_SLAP_POST_SYSTEM,
670  "system() string to execute after tests have completed.",
671  &post_system, &post_system,
672  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
673  {"pre-query", OPT_SLAP_PRE_QUERY,
674  "Query to run or file containing query to execute before running tests.",
675  &user_supplied_pre_statements, &user_supplied_pre_statements,
676  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
677  {"pre-system", OPT_SLAP_PRE_SYSTEM,
678  "system() string to execute before running tests.",
679  &pre_system, &pre_system,
680  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
681  {"protocol", OPT_MYSQL_PROTOCOL,
682  "The protocol to use for connection (tcp, socket, pipe, memory).",
683  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
684  {"query", 'q', "Query to run or file containing query to run.",
685  &user_supplied_query, &user_supplied_query,
686  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
687 #ifdef HAVE_SMEM
688  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
689  "Base name of shared memory.", &shared_memory_base_name,
690  &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
691  0, 0, 0, 0, 0, 0},
692 #endif
693  {"silent", 's', "Run program in silent mode - no output.",
694  &opt_silent, &opt_silent, 0, GET_BOOL, NO_ARG,
695  0, 0, 0, 0, 0, 0},
696  {"socket", 'S', "The socket file to use for connection.",
697  &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR,
698  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
699 #include <sslopt-longopts.h>
700 #ifndef DONT_ALLOW_USER_CHANGE
701  {"user", 'u', "User for login if not current user.", &user,
702  &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
703 #endif
704  {"verbose", 'v',
705  "More verbose output; you can use this multiple times to get even more "
706  "verbose output.", &verbose, &verbose, 0, GET_NO_ARG, NO_ARG,
707  0, 0, 0, 0, 0, 0},
708  {"version", 'V', "Output version information and exit.", 0, 0, 0,
709  GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
710  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
711 };
712 
713 
714 static void print_version(void)
715 {
716  printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
717  MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
718 }
719 
720 
721 static void usage(void)
722 {
723  print_version();
724  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2005"));
725  puts("Run a query multiple times against the server.\n");
726  printf("Usage: %s [OPTIONS]\n",my_progname);
727  print_defaults("my",load_default_groups);
728  my_print_help(my_long_options);
729 }
730 
731 
732 static my_bool
733 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
734  char *argument)
735 {
736  DBUG_ENTER("get_one_option");
737  switch(optid) {
738  case 'v':
739  verbose++;
740  break;
741  case 'p':
742  if (argument == disabled_my_option)
743  argument= (char*) ""; /* Don't require password */
744  if (argument)
745  {
746  char *start= argument;
747  my_free(opt_password);
748  opt_password= my_strdup(argument,MYF(MY_FAE));
749  while (*argument) *argument++= 'x'; /* Destroy argument */
750  if (*start)
751  start[1]= 0; /* Cut length of argument */
752  tty_password= 0;
753  }
754  else
755  tty_password= 1;
756  break;
757  case 'W':
758 #ifdef __WIN__
759  opt_protocol= MYSQL_PROTOCOL_PIPE;
760 #endif
761  break;
762  case OPT_MYSQL_PROTOCOL:
763  opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
764  opt->name);
765  break;
766  case '#':
767  DBUG_PUSH(argument ? argument : default_dbug_option);
768  debug_check_flag= 1;
769  break;
770  case OPT_SLAP_CSV:
771  if (!argument)
772  argument= (char *)"-"; /* use stdout */
773  opt_csv_str= argument;
774  break;
775 #include <sslopt-case.h>
776  case 'V':
777  print_version();
778  exit(0);
779  break;
780  case '?':
781  case 'I': /* Info */
782  usage();
783  exit(0);
784  case OPT_ENABLE_CLEARTEXT_PLUGIN:
785  using_opt_enable_cleartext_plugin= TRUE;
786  break;
787  }
788  DBUG_RETURN(0);
789 }
790 
791 
792 uint
793 get_random_string(char *buf)
794 {
795  char *buf_ptr= buf;
796  int x;
797  DBUG_ENTER("get_random_string");
798  for (x= RAND_STRING_SIZE; x > 0; x--)
799  *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
800  DBUG_RETURN(buf_ptr - buf);
801 }
802 
803 
804 /*
805  build_table_string
806 
807  This function builds a create table query if the user opts to not supply
808  a file or string containing a create table statement
809 */
810 static statement *
811 build_table_string(void)
812 {
813  char buf[HUGE_STRING_LENGTH];
814  unsigned int col_count;
815  statement *ptr;
816  DYNAMIC_STRING table_string;
817  DBUG_ENTER("build_table_string");
818 
819  DBUG_PRINT("info", ("num int cols %u num char cols %u",
820  num_int_cols, num_char_cols));
821 
822  init_dynamic_string(&table_string, "", 1024, 1024);
823 
824  dynstr_append(&table_string, "CREATE TABLE `t1` (");
825 
826  if (auto_generate_sql_autoincrement)
827  {
828  dynstr_append(&table_string, "id serial");
829 
830  if (num_int_cols || num_char_cols)
831  dynstr_append(&table_string, ",");
832  }
833 
834  if (auto_generate_sql_guid_primary)
835  {
836  dynstr_append(&table_string, "id varchar(32) primary key");
837 
838  if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
839  dynstr_append(&table_string, ",");
840  }
841 
842  if (auto_generate_sql_secondary_indexes)
843  {
844  unsigned int count;
845 
846  for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
847  {
848  if (count) /* Except for the first pass we add a comma */
849  dynstr_append(&table_string, ",");
850 
851  if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
852  > HUGE_STRING_LENGTH)
853  {
854  fprintf(stderr, "Memory Allocation error in create table\n");
855  exit(1);
856  }
857  dynstr_append(&table_string, buf);
858  }
859 
860  if (num_int_cols || num_char_cols)
861  dynstr_append(&table_string, ",");
862  }
863 
864  if (num_int_cols)
865  for (col_count= 1; col_count <= num_int_cols; col_count++)
866  {
867  if (num_int_cols_index)
868  {
869  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)",
870  col_count, col_count) > HUGE_STRING_LENGTH)
871  {
872  fprintf(stderr, "Memory Allocation error in create table\n");
873  exit(1);
874  }
875  }
876  else
877  {
878  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count)
879  > HUGE_STRING_LENGTH)
880  {
881  fprintf(stderr, "Memory Allocation error in create table\n");
882  exit(1);
883  }
884  }
885  dynstr_append(&table_string, buf);
886 
887  if (col_count < num_int_cols || num_char_cols > 0)
888  dynstr_append(&table_string, ",");
889  }
890 
891  if (num_char_cols)
892  for (col_count= 1; col_count <= num_char_cols; col_count++)
893  {
894  if (num_char_cols_index)
895  {
896  if (snprintf(buf, HUGE_STRING_LENGTH,
897  "charcol%d VARCHAR(128), INDEX(charcol%d) ",
898  col_count, col_count) > HUGE_STRING_LENGTH)
899  {
900  fprintf(stderr, "Memory Allocation error in creating table\n");
901  exit(1);
902  }
903  }
904  else
905  {
906  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
907  col_count) > HUGE_STRING_LENGTH)
908  {
909  fprintf(stderr, "Memory Allocation error in creating table\n");
910  exit(1);
911  }
912  }
913  dynstr_append(&table_string, buf);
914 
915  if (col_count < num_char_cols)
916  dynstr_append(&table_string, ",");
917  }
918 
919  dynstr_append(&table_string, ")");
920  ptr= (statement *)my_malloc(sizeof(statement),
921  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
922  ptr->string = (char *)my_malloc(table_string.length+1,
923  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
924  ptr->length= table_string.length+1;
925  ptr->type= CREATE_TABLE_TYPE;
926  strmov(ptr->string, table_string.str);
927  dynstr_free(&table_string);
928  DBUG_RETURN(ptr);
929 }
930 
931 /*
932  build_update_string()
933 
934  This function builds insert statements when the user opts to not supply
935  an insert file or string containing insert data
936 */
937 static statement *
938 build_update_string(void)
939 {
940  char buf[HUGE_STRING_LENGTH];
941  unsigned int col_count;
942  statement *ptr;
943  DYNAMIC_STRING update_string;
944  DBUG_ENTER("build_update_string");
945 
946  init_dynamic_string(&update_string, "", 1024, 1024);
947 
948  dynstr_append(&update_string, "UPDATE t1 SET ");
949 
950  if (num_int_cols)
951  for (col_count= 1; col_count <= num_int_cols; col_count++)
952  {
953  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
954  random()) > HUGE_STRING_LENGTH)
955  {
956  fprintf(stderr, "Memory Allocation error in creating update\n");
957  exit(1);
958  }
959  dynstr_append(&update_string, buf);
960 
961  if (col_count < num_int_cols || num_char_cols > 0)
962  dynstr_append_mem(&update_string, ",", 1);
963  }
964 
965  if (num_char_cols)
966  for (col_count= 1; col_count <= num_char_cols; col_count++)
967  {
968  char rand_buffer[RAND_STRING_SIZE];
969  int buf_len= get_random_string(rand_buffer);
970 
971  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
972  buf_len, rand_buffer)
973  > HUGE_STRING_LENGTH)
974  {
975  fprintf(stderr, "Memory Allocation error in creating update\n");
976  exit(1);
977  }
978  dynstr_append(&update_string, buf);
979 
980  if (col_count < num_char_cols)
981  dynstr_append_mem(&update_string, ",", 1);
982  }
983 
984  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
985  dynstr_append(&update_string, " WHERE id = ");
986 
987 
988  ptr= (statement *)my_malloc(sizeof(statement),
989  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
990 
991  ptr->string= (char *)my_malloc(update_string.length + 1,
992  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
993  ptr->length= update_string.length+1;
994  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
995  ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
996  else
997  ptr->type= UPDATE_TYPE;
998  strmov(ptr->string, update_string.str);
999  dynstr_free(&update_string);
1000  DBUG_RETURN(ptr);
1001 }
1002 
1003 
1004 /*
1005  build_insert_string()
1006 
1007  This function builds insert statements when the user opts to not supply
1008  an insert file or string containing insert data
1009 */
1010 static statement *
1011 build_insert_string(void)
1012 {
1013  char buf[HUGE_STRING_LENGTH];
1014  unsigned int col_count;
1015  statement *ptr;
1016  DYNAMIC_STRING insert_string;
1017  DBUG_ENTER("build_insert_string");
1018 
1019  init_dynamic_string(&insert_string, "", 1024, 1024);
1020 
1021  dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
1022 
1023  if (auto_generate_sql_autoincrement)
1024  {
1025  dynstr_append(&insert_string, "NULL");
1026 
1027  if (num_int_cols || num_char_cols)
1028  dynstr_append(&insert_string, ",");
1029  }
1030 
1031  if (auto_generate_sql_guid_primary)
1032  {
1033  dynstr_append(&insert_string, "uuid()");
1034 
1035  if (num_int_cols || num_char_cols)
1036  dynstr_append(&insert_string, ",");
1037  }
1038 
1039  if (auto_generate_sql_secondary_indexes)
1040  {
1041  unsigned int count;
1042 
1043  for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1044  {
1045  if (count) /* Except for the first pass we add a comma */
1046  dynstr_append(&insert_string, ",");
1047 
1048  dynstr_append(&insert_string, "uuid()");
1049  }
1050 
1051  if (num_int_cols || num_char_cols)
1052  dynstr_append(&insert_string, ",");
1053  }
1054 
1055  if (num_int_cols)
1056  for (col_count= 1; col_count <= num_int_cols; col_count++)
1057  {
1058  if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1059  {
1060  fprintf(stderr, "Memory Allocation error in creating insert\n");
1061  exit(1);
1062  }
1063  dynstr_append(&insert_string, buf);
1064 
1065  if (col_count < num_int_cols || num_char_cols > 0)
1066  dynstr_append_mem(&insert_string, ",", 1);
1067  }
1068 
1069  if (num_char_cols)
1070  for (col_count= 1; col_count <= num_char_cols; col_count++)
1071  {
1072  int buf_len= get_random_string(buf);
1073  dynstr_append_mem(&insert_string, "'", 1);
1074  dynstr_append_mem(&insert_string, buf, buf_len);
1075  dynstr_append_mem(&insert_string, "'", 1);
1076 
1077  if (col_count < num_char_cols)
1078  dynstr_append_mem(&insert_string, ",", 1);
1079  }
1080 
1081  dynstr_append_mem(&insert_string, ")", 1);
1082 
1083  ptr= (statement *)my_malloc(sizeof(statement),
1084  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1085  ptr->string= (char *)my_malloc(insert_string.length + 1,
1086  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1087  ptr->length= insert_string.length+1;
1088  ptr->type= INSERT_TYPE;
1089  strmov(ptr->string, insert_string.str);
1090  dynstr_free(&insert_string);
1091  DBUG_RETURN(ptr);
1092 }
1093 
1094 
1095 /*
1096  build_select_string()
1097 
1098  This function builds a query if the user opts to not supply a query
1099  statement or file containing a query statement
1100 */
1101 static statement *
1102 build_select_string(my_bool key)
1103 {
1104  char buf[HUGE_STRING_LENGTH];
1105  unsigned int col_count;
1106  statement *ptr;
1107  static DYNAMIC_STRING query_string;
1108  DBUG_ENTER("build_select_string");
1109 
1110  init_dynamic_string(&query_string, "", 1024, 1024);
1111 
1112  dynstr_append_mem(&query_string, "SELECT ", 7);
1113  for (col_count= 1; col_count <= num_int_cols; col_count++)
1114  {
1115  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1116  > HUGE_STRING_LENGTH)
1117  {
1118  fprintf(stderr, "Memory Allocation error in creating select\n");
1119  exit(1);
1120  }
1121  dynstr_append(&query_string, buf);
1122 
1123  if (col_count < num_int_cols || num_char_cols > 0)
1124  dynstr_append_mem(&query_string, ",", 1);
1125 
1126  }
1127  for (col_count= 1; col_count <= num_char_cols; col_count++)
1128  {
1129  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1130  > HUGE_STRING_LENGTH)
1131  {
1132  fprintf(stderr, "Memory Allocation error in creating select\n");
1133  exit(1);
1134  }
1135  dynstr_append(&query_string, buf);
1136 
1137  if (col_count < num_char_cols)
1138  dynstr_append_mem(&query_string, ",", 1);
1139 
1140  }
1141  dynstr_append(&query_string, " FROM t1");
1142 
1143  if ((key) &&
1144  (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1145  dynstr_append(&query_string, " WHERE id = ");
1146 
1147  ptr= (statement *)my_malloc(sizeof(statement),
1148  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1149  ptr->string= (char *)my_malloc(query_string.length + 1,
1150  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1151  ptr->length= query_string.length+1;
1152  if ((key) &&
1153  (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1154  ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1155  else
1156  ptr->type= SELECT_TYPE;
1157  strmov(ptr->string, query_string.str);
1158  dynstr_free(&query_string);
1159  DBUG_RETURN(ptr);
1160 }
1161 
1162 static int
1163 get_options(int *argc,char ***argv)
1164 {
1165  int ho_error;
1166  char *tmp_string;
1167  MY_STAT sbuf; /* Stat information for the data file */
1168 
1169  DBUG_ENTER("get_options");
1170  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1171  exit(ho_error);
1172  if (debug_info_flag)
1173  my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1174  if (debug_check_flag)
1175  my_end_arg= MY_CHECK_ERROR;
1176 
1177  if (!user)
1178  user= (char *)"root";
1179 
1180  /*
1181  If something is created and --no-drop is not specified, we drop the
1182  schema.
1183  */
1184  if (!opt_no_drop && (create_string || auto_generate_sql))
1185  opt_preserve= FALSE;
1186 
1187  if (auto_generate_sql && (create_string || user_supplied_query))
1188  {
1189  fprintf(stderr,
1190  "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1191  my_progname);
1192  exit(1);
1193  }
1194 
1195  if (auto_generate_sql && auto_generate_sql_guid_primary &&
1196  auto_generate_sql_autoincrement)
1197  {
1198  fprintf(stderr,
1199  "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1200  my_progname);
1201  exit(1);
1202  }
1203 
1204  /*
1205  We are testing to make sure that if someone specified a key search
1206  that we actually added a key!
1207  */
1208  if (auto_generate_sql && auto_generate_sql_type[0] == 'k')
1209  if ( auto_generate_sql_autoincrement == FALSE &&
1210  auto_generate_sql_guid_primary == FALSE)
1211  {
1212  fprintf(stderr,
1213  "%s: Can't perform key test without a primary key!\n",
1214  my_progname);
1215  exit(1);
1216  }
1217 
1218 
1219 
1220  if (auto_generate_sql && num_of_query && auto_actual_queries)
1221  {
1222  fprintf(stderr,
1223  "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1224  my_progname);
1225  exit(1);
1226  }
1227 
1228  parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1229 
1230  if (opt_csv_str)
1231  {
1232  opt_silent= TRUE;
1233 
1234  if (opt_csv_str[0] == '-')
1235  {
1236  csv_file= my_fileno(stdout);
1237  }
1238  else
1239  {
1240  if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1241  == -1)
1242  {
1243  fprintf(stderr,"%s: Could not open csv file: %sn\n",
1244  my_progname, opt_csv_str);
1245  exit(1);
1246  }
1247  }
1248  }
1249 
1250  if (opt_only_print)
1251  opt_silent= TRUE;
1252 
1253  if (num_int_cols_opt)
1254  {
1255  option_string *str;
1256  parse_option(num_int_cols_opt, &str, ',');
1257  num_int_cols= atoi(str->string);
1258  if (str->option)
1259  num_int_cols_index= atoi(str->option);
1260  option_cleanup(str);
1261  }
1262 
1263  if (num_char_cols_opt)
1264  {
1265  option_string *str;
1266  parse_option(num_char_cols_opt, &str, ',');
1267  num_char_cols= atoi(str->string);
1268  if (str->option)
1269  num_char_cols_index= atoi(str->option);
1270  else
1271  num_char_cols_index= 0;
1272  option_cleanup(str);
1273  }
1274 
1275 
1276  if (auto_generate_sql)
1277  {
1278  unsigned long long x= 0;
1279  statement *ptr_statement;
1280 
1281  if (verbose >= 2)
1282  printf("Building Create Statements for Auto\n");
1283 
1284  create_statements= build_table_string();
1285  /*
1286  Pre-populate table
1287  */
1288  for (ptr_statement= create_statements, x= 0;
1289  x < auto_generate_sql_unique_write_number;
1290  x++, ptr_statement= ptr_statement->next)
1291  {
1292  ptr_statement->next= build_insert_string();
1293  }
1294 
1295  if (verbose >= 2)
1296  printf("Building Query Statements for Auto\n");
1297 
1298  if (auto_generate_sql_type[0] == 'r')
1299  {
1300  if (verbose >= 2)
1301  printf("Generating SELECT Statements for Auto\n");
1302 
1303  query_statements= build_select_string(FALSE);
1304  for (ptr_statement= query_statements, x= 0;
1305  x < auto_generate_sql_unique_query_number;
1306  x++, ptr_statement= ptr_statement->next)
1307  {
1308  ptr_statement->next= build_select_string(FALSE);
1309  }
1310  }
1311  else if (auto_generate_sql_type[0] == 'k')
1312  {
1313  if (verbose >= 2)
1314  printf("Generating SELECT for keys Statements for Auto\n");
1315 
1316  query_statements= build_select_string(TRUE);
1317  for (ptr_statement= query_statements, x= 0;
1318  x < auto_generate_sql_unique_query_number;
1319  x++, ptr_statement= ptr_statement->next)
1320  {
1321  ptr_statement->next= build_select_string(TRUE);
1322  }
1323  }
1324  else if (auto_generate_sql_type[0] == 'w')
1325  {
1326  /*
1327  We generate a number of strings in case the engine is
1328  Archive (since strings which were identical one after another
1329  would be too easily optimized).
1330  */
1331  if (verbose >= 2)
1332  printf("Generating INSERT Statements for Auto\n");
1333  query_statements= build_insert_string();
1334  for (ptr_statement= query_statements, x= 0;
1335  x < auto_generate_sql_unique_query_number;
1336  x++, ptr_statement= ptr_statement->next)
1337  {
1338  ptr_statement->next= build_insert_string();
1339  }
1340  }
1341  else if (auto_generate_sql_type[0] == 'u')
1342  {
1343  query_statements= build_update_string();
1344  for (ptr_statement= query_statements, x= 0;
1345  x < auto_generate_sql_unique_query_number;
1346  x++, ptr_statement= ptr_statement->next)
1347  {
1348  ptr_statement->next= build_update_string();
1349  }
1350  }
1351  else /* Mixed mode is default */
1352  {
1353  int coin= 0;
1354 
1355  query_statements= build_insert_string();
1356  /*
1357  This logic should be extended to do a more mixed load,
1358  at the moment it results in "every other".
1359  */
1360  for (ptr_statement= query_statements, x= 0;
1361  x < auto_generate_sql_unique_query_number;
1362  x++, ptr_statement= ptr_statement->next)
1363  {
1364  if (coin)
1365  {
1366  ptr_statement->next= build_insert_string();
1367  coin= 0;
1368  }
1369  else
1370  {
1371  ptr_statement->next= build_select_string(TRUE);
1372  coin= 1;
1373  }
1374  }
1375  }
1376  }
1377  else
1378  {
1379  if (create_string && my_stat(create_string, &sbuf, MYF(0)))
1380  {
1381  File data_file;
1382  if (!MY_S_ISREG(sbuf.st_mode))
1383  {
1384  fprintf(stderr,"%s: Create file was not a regular file\n",
1385  my_progname);
1386  exit(1);
1387  }
1388  if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1389  {
1390  fprintf(stderr,"%s: Could not open create file\n", my_progname);
1391  exit(1);
1392  }
1393  tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1394  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1395  my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1396  tmp_string[sbuf.st_size]= '\0';
1397  my_close(data_file,MYF(0));
1398  parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1399  my_free(tmp_string);
1400  }
1401  else if (create_string)
1402  {
1403  parse_delimiter(create_string, &create_statements, delimiter[0]);
1404  }
1405 
1406  if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0)))
1407  {
1408  File data_file;
1409  if (!MY_S_ISREG(sbuf.st_mode))
1410  {
1411  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1412  my_progname);
1413  exit(1);
1414  }
1415  if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1416  {
1417  fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1418  exit(1);
1419  }
1420  tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1421  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1422  my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1423  tmp_string[sbuf.st_size]= '\0';
1424  my_close(data_file,MYF(0));
1425  if (user_supplied_query)
1426  actual_queries= parse_delimiter(tmp_string, &query_statements,
1427  delimiter[0]);
1428  my_free(tmp_string);
1429  }
1430  else if (user_supplied_query)
1431  {
1432  actual_queries= parse_delimiter(user_supplied_query, &query_statements,
1433  delimiter[0]);
1434  }
1435  }
1436 
1437  if (user_supplied_pre_statements && my_stat(user_supplied_pre_statements, &sbuf, MYF(0)))
1438  {
1439  File data_file;
1440  if (!MY_S_ISREG(sbuf.st_mode))
1441  {
1442  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1443  my_progname);
1444  exit(1);
1445  }
1446  if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1447  {
1448  fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1449  exit(1);
1450  }
1451  tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1452  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1453  my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1454  tmp_string[sbuf.st_size]= '\0';
1455  my_close(data_file,MYF(0));
1456  if (user_supplied_pre_statements)
1457  (void)parse_delimiter(tmp_string, &pre_statements,
1458  delimiter[0]);
1459  my_free(tmp_string);
1460  }
1461  else if (user_supplied_pre_statements)
1462  {
1463  (void)parse_delimiter(user_supplied_pre_statements,
1464  &pre_statements,
1465  delimiter[0]);
1466  }
1467 
1468  if (user_supplied_post_statements && my_stat(user_supplied_post_statements, &sbuf, MYF(0)))
1469  {
1470  File data_file;
1471  if (!MY_S_ISREG(sbuf.st_mode))
1472  {
1473  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1474  my_progname);
1475  exit(1);
1476  }
1477  if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1478  {
1479  fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1480  exit(1);
1481  }
1482  tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1483  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1484  my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1485  tmp_string[sbuf.st_size]= '\0';
1486  my_close(data_file,MYF(0));
1487  if (user_supplied_post_statements)
1488  (void)parse_delimiter(tmp_string, &post_statements,
1489  delimiter[0]);
1490  my_free(tmp_string);
1491  }
1492  else if (user_supplied_post_statements)
1493  {
1494  (void)parse_delimiter(user_supplied_post_statements, &post_statements,
1495  delimiter[0]);
1496  }
1497 
1498  if (verbose >= 2)
1499  printf("Parsing engines to use.\n");
1500 
1501  if (default_engine)
1502  parse_option(default_engine, &engine_options, ',');
1503 
1504  if (tty_password)
1505  opt_password= get_tty_password(NullS);
1506  DBUG_RETURN(0);
1507 }
1508 
1509 
1510 static int run_query(MYSQL *mysql, const char *query, int len)
1511 {
1512  if (opt_only_print)
1513  {
1514  printf("%.*s;\n", len, query);
1515  return 0;
1516  }
1517 
1518  if (verbose >= 3)
1519  printf("%.*s;\n", len, query);
1520  return mysql_real_query(mysql, query, len);
1521 }
1522 
1523 
1524 static int
1525 generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1526 {
1527  MYSQL_RES *result;
1528  MYSQL_ROW row;
1529  unsigned long long counter;
1530  DBUG_ENTER("generate_primary_key_list");
1531 
1532  /*
1533  Blackhole is a special case, this allows us to test the upper end
1534  of the server during load runs.
1535  */
1536  if (opt_only_print || (engine_stmt &&
1537  strstr(engine_stmt->string, "blackhole")))
1538  {
1539  primary_keys_number_of= 1;
1540  primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1541  primary_keys_number_of),
1542  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1543  /* Yes, we strdup a const string to simplify the interface */
1544  primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0));
1545  }
1546  else
1547  {
1548  if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1549  {
1550  fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1551  mysql_error(mysql));
1552  exit(1);
1553  }
1554 
1555  if (!(result= mysql_store_result(mysql)))
1556  {
1557  fprintf(stderr, "%s: Error when storing result: %d %s\n",
1558  my_progname, mysql_errno(mysql), mysql_error(mysql));
1559  exit(1);
1560  }
1561  primary_keys_number_of= mysql_num_rows(result);
1562 
1563  /* So why check this? Blackhole :) */
1564  if (primary_keys_number_of)
1565  {
1566  /*
1567  We create the structure and loop and create the items.
1568  */
1569  primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1570  primary_keys_number_of),
1571  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1572  row= mysql_fetch_row(result);
1573  for (counter= 0; counter < primary_keys_number_of;
1574  counter++, row= mysql_fetch_row(result))
1575  primary_keys[counter]= my_strdup(row[0], MYF(0));
1576  }
1577 
1578  mysql_free_result(result);
1579  }
1580 
1581  DBUG_RETURN(0);
1582 }
1583 
1584 static int
1585 drop_primary_key_list(void)
1586 {
1587  unsigned long long counter;
1588 
1589  if (primary_keys_number_of)
1590  {
1591  for (counter= 0; counter < primary_keys_number_of; counter++)
1592  my_free(primary_keys[counter]);
1593 
1594  my_free(primary_keys);
1595  }
1596 
1597  return 0;
1598 }
1599 
1600 static int
1601 create_schema(MYSQL *mysql, const char *db, statement *stmt,
1602  option_string *engine_stmt)
1603 {
1604  char query[HUGE_STRING_LENGTH];
1605  statement *ptr;
1606  statement *after_create;
1607  int len;
1608  ulonglong count;
1609  DBUG_ENTER("create_schema");
1610 
1611  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1612 
1613  if (verbose >= 2)
1614  printf("Loading Pre-data\n");
1615 
1616  if (run_query(mysql, query, len))
1617  {
1618  fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1619  mysql_error(mysql));
1620  exit(1);
1621  }
1622 
1623  if (opt_only_print)
1624  {
1625  printf("use %s;\n", db);
1626  }
1627  else
1628  {
1629  if (verbose >= 3)
1630  printf("%s;\n", query);
1631 
1632  if (mysql_select_db(mysql, db))
1633  {
1634  fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1635  mysql_error(mysql));
1636  exit(1);
1637  }
1638  }
1639 
1640  if (engine_stmt)
1641  {
1642  len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1643  engine_stmt->string);
1644  if (run_query(mysql, query, len))
1645  {
1646  fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
1647  mysql_error(mysql));
1648  exit(1);
1649  }
1650  }
1651 
1652  count= 0;
1653  after_create= stmt;
1654 
1655 limit_not_met:
1656  for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1657  {
1658  if (auto_generate_sql && ( auto_generate_sql_number == count))
1659  break;
1660 
1661  if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1662  {
1663  char buffer[HUGE_STRING_LENGTH];
1664 
1665  snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
1666  engine_stmt->option);
1667  if (run_query(mysql, buffer, strlen(buffer)))
1668  {
1669  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1670  my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1671  exit(1);
1672  }
1673  }
1674  else
1675  {
1676  if (run_query(mysql, ptr->string, ptr->length))
1677  {
1678  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1679  my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1680  exit(1);
1681  }
1682  }
1683  }
1684 
1685  if (auto_generate_sql && (auto_generate_sql_number > count ))
1686  {
1687  /* Special case for auto create, we don't want to create tables twice */
1688  after_create= stmt->next;
1689  goto limit_not_met;
1690  }
1691 
1692  DBUG_RETURN(0);
1693 }
1694 
1695 static int
1696 drop_schema(MYSQL *mysql, const char *db)
1697 {
1698  char query[HUGE_STRING_LENGTH];
1699  int len;
1700  DBUG_ENTER("drop_schema");
1701  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1702 
1703  if (run_query(mysql, query, len))
1704  {
1705  fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1706  my_progname, db, mysql_error(mysql));
1707  exit(1);
1708  }
1709 
1710 
1711 
1712  DBUG_RETURN(0);
1713 }
1714 
1715 static int
1716 run_statements(MYSQL *mysql, statement *stmt)
1717 {
1718  statement *ptr;
1719  MYSQL_RES *result;
1720  DBUG_ENTER("run_statements");
1721 
1722  for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1723  {
1724  if (run_query(mysql, ptr->string, ptr->length))
1725  {
1726  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1727  my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1728  exit(1);
1729  }
1730  if (mysql_field_count(mysql))
1731  {
1732  result= mysql_store_result(mysql);
1733  mysql_free_result(result);
1734  }
1735  }
1736 
1737  DBUG_RETURN(0);
1738 }
1739 
1740 static int
1741 run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit)
1742 {
1743  uint x;
1744  struct timeval start_time, end_time;
1745  thread_context con;
1746  pthread_t mainthread; /* Thread descriptor */
1747  pthread_attr_t attr; /* Thread attributes */
1748  DBUG_ENTER("run_scheduler");
1749 
1750  con.stmt= stmts;
1751  con.limit= limit;
1752 
1753  pthread_attr_init(&attr);
1754  pthread_attr_setdetachstate(&attr,
1755  PTHREAD_CREATE_DETACHED);
1756 
1757  pthread_mutex_lock(&counter_mutex);
1758  thread_counter= 0;
1759 
1760  pthread_mutex_lock(&sleeper_mutex);
1761  master_wakeup= 1;
1762  pthread_mutex_unlock(&sleeper_mutex);
1763  for (x= 0; x < concur; x++)
1764  {
1765  /* now you create the thread */
1766  if (pthread_create(&mainthread, &attr, run_task,
1767  (void *)&con) != 0)
1768  {
1769  fprintf(stderr,"%s: Could not create thread\n",
1770  my_progname);
1771  exit(0);
1772  }
1773  thread_counter++;
1774  }
1775  pthread_mutex_unlock(&counter_mutex);
1776  pthread_attr_destroy(&attr);
1777 
1778  pthread_mutex_lock(&sleeper_mutex);
1779  master_wakeup= 0;
1780  pthread_mutex_unlock(&sleeper_mutex);
1781  pthread_cond_broadcast(&sleep_threshhold);
1782 
1783  gettimeofday(&start_time, NULL);
1784 
1785  /*
1786  We loop until we know that all children have cleaned up.
1787  */
1788  pthread_mutex_lock(&counter_mutex);
1789  while (thread_counter)
1790  {
1791  struct timespec abstime;
1792 
1793  set_timespec(abstime, 3);
1794  pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1795  }
1796  pthread_mutex_unlock(&counter_mutex);
1797 
1798  gettimeofday(&end_time, NULL);
1799 
1800 
1801  sptr->timing= timedif(end_time, start_time);
1802  sptr->users= concur;
1803  sptr->rows= limit;
1804 
1805  DBUG_RETURN(0);
1806 }
1807 
1808 
1809 pthread_handler_t run_task(void *p)
1810 {
1811  ulonglong counter= 0, queries;
1812  ulonglong detach_counter;
1813  unsigned int commit_counter;
1814  MYSQL *mysql;
1815  MYSQL_RES *result;
1816  MYSQL_ROW row;
1817  statement *ptr;
1818  thread_context *con= (thread_context *)p;
1819 
1820  DBUG_ENTER("run_task");
1821  DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : ""));
1822 
1823  pthread_mutex_lock(&sleeper_mutex);
1824  while (master_wakeup)
1825  {
1826  pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
1827  }
1828  pthread_mutex_unlock(&sleeper_mutex);
1829 
1830  if (!(mysql= mysql_init(NULL)))
1831  {
1832  fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1833  my_progname, mysql_error(mysql));
1834  exit(0);
1835  }
1836 
1837  if (mysql_thread_init())
1838  {
1839  fprintf(stderr,"%s: mysql_thread_init() failed ERROR : %s\n",
1840  my_progname, mysql_error(mysql));
1841  exit(0);
1842  }
1843 
1844  DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user));
1845 
1846  if (!opt_only_print)
1847  {
1848  if (slap_connect(mysql))
1849  goto end;
1850  }
1851 
1852  DBUG_PRINT("info", ("connected."));
1853  if (verbose >= 3)
1854  printf("connected!\n");
1855  queries= 0;
1856 
1857  commit_counter= 0;
1858  if (commit_rate)
1859  run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
1860 
1861 limit_not_met:
1862  for (ptr= con->stmt, detach_counter= 0;
1863  ptr && ptr->length;
1864  ptr= ptr->next, detach_counter++)
1865  {
1866  if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
1867  {
1868  mysql_close(mysql);
1869 
1870  if (!(mysql= mysql_init(NULL)))
1871  {
1872  fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1873  my_progname, mysql_error(mysql));
1874  exit(0);
1875  }
1876 
1877  if (slap_connect(mysql))
1878  goto end;
1879  }
1880 
1881  /*
1882  We have to execute differently based on query type. This should become a function.
1883  */
1884  if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
1885  (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
1886  {
1887  int length;
1888  unsigned int key_val;
1889  char *key;
1890  char buffer[HUGE_STRING_LENGTH];
1891 
1892  /*
1893  This should only happen if some sort of new engine was
1894  implemented that didn't properly handle UPDATEs.
1895 
1896  Just in case someone runs this under an experimental engine we don't
1897  want a crash so the if() is placed here.
1898  */
1899  DBUG_ASSERT(primary_keys_number_of);
1900  if (primary_keys_number_of)
1901  {
1902  key_val= (unsigned int)(random() % primary_keys_number_of);
1903  key= primary_keys[key_val];
1904 
1905  DBUG_ASSERT(key);
1906 
1907  length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
1908  (int)ptr->length, ptr->string, key);
1909 
1910  if (run_query(mysql, buffer, length))
1911  {
1912  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1913  my_progname, (uint)length, buffer, mysql_error(mysql));
1914  exit(0);
1915  }
1916  }
1917  }
1918  else
1919  {
1920  if (run_query(mysql, ptr->string, ptr->length))
1921  {
1922  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1923  my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1924  exit(0);
1925  }
1926  }
1927 
1928  do
1929  {
1930  if (mysql_field_count(mysql))
1931  {
1932  if (!(result= mysql_store_result(mysql)))
1933  fprintf(stderr, "%s: Error when storing result: %d %s\n",
1934  my_progname, mysql_errno(mysql), mysql_error(mysql));
1935  else
1936  {
1937  while ((row= mysql_fetch_row(result)))
1938  counter++;
1939  mysql_free_result(result);
1940  }
1941  }
1942  } while(mysql_next_result(mysql) == 0);
1943  queries++;
1944 
1945  if (commit_rate && (++commit_counter == commit_rate))
1946  {
1947  commit_counter= 0;
1948  run_query(mysql, "COMMIT", strlen("COMMIT"));
1949  }
1950 
1951  if (con->limit && queries == con->limit)
1952  goto end;
1953  }
1954 
1955  if (con->limit && queries < con->limit)
1956  goto limit_not_met;
1957 
1958 end:
1959  if (commit_rate)
1960  run_query(mysql, "COMMIT", strlen("COMMIT"));
1961 
1962  if (!opt_only_print)
1963  mysql_close(mysql);
1964 
1965  mysql_thread_end();
1966 
1967  pthread_mutex_lock(&counter_mutex);
1968  thread_counter--;
1969  pthread_cond_signal(&count_threshhold);
1970  pthread_mutex_unlock(&counter_mutex);
1971 
1972  DBUG_RETURN(0);
1973 }
1974 
1975 uint
1976 parse_option(const char *origin, option_string **stmt, char delm)
1977 {
1978  char *retstr;
1979  char *ptr= (char *)origin;
1980  option_string **sptr= stmt;
1981  option_string *tmp;
1982  size_t length= strlen(origin);
1983  uint count= 0; /* We know that there is always one */
1984 
1985  for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
1986  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1987  (retstr= strchr(ptr, delm));
1988  tmp->next= (option_string *)my_malloc(sizeof(option_string),
1989  MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
1990  tmp= tmp->next)
1991  {
1992  char buffer[HUGE_STRING_LENGTH];
1993  char *buffer_ptr;
1994 
1995  count++;
1996  strncpy(buffer, ptr, (size_t)(retstr - ptr));
1997  if ((buffer_ptr= strchr(buffer, ':')))
1998  {
1999  char *option_ptr;
2000 
2001  tmp->length= (size_t)(buffer_ptr - buffer);
2002  tmp->string= my_strndup(ptr, (uint)tmp->length, MYF(MY_FAE));
2003 
2004  option_ptr= ptr + 1 + tmp->length;
2005 
2006  /* Move past the : and the first string */
2007  tmp->option_length= (size_t)(retstr - option_ptr);
2008  tmp->option= my_strndup(option_ptr, (uint)tmp->option_length,
2009  MYF(MY_FAE));
2010  }
2011  else
2012  {
2013  tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
2014  tmp->length= (size_t)(retstr - ptr);
2015  }
2016 
2017  ptr+= retstr - ptr + 1;
2018  if (isspace(*ptr))
2019  ptr++;
2020  count++;
2021  }
2022 
2023  if (ptr != origin+length)
2024  {
2025  char *origin_ptr;
2026 
2027  if ((origin_ptr= strchr(ptr, ':')))
2028  {
2029  char *option_ptr;
2030 
2031  tmp->length= (size_t)(origin_ptr - ptr);
2032  tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE));
2033 
2034  option_ptr= (char *)ptr + 1 + tmp->length;
2035 
2036  /* Move past the : and the first string */
2037  tmp->option_length= (size_t)((ptr + length) - option_ptr);
2038  tmp->option= my_strndup(option_ptr, tmp->option_length,
2039  MYF(MY_FAE));
2040  }
2041  else
2042  {
2043  tmp->length= (size_t)((ptr + length) - ptr);
2044  tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
2045  }
2046 
2047  count++;
2048  }
2049 
2050  return count;
2051 }
2052 
2053 
2054 uint
2055 parse_delimiter(const char *script, statement **stmt, char delm)
2056 {
2057  char *retstr;
2058  char *ptr= (char *)script;
2059  statement **sptr= stmt;
2060  statement *tmp;
2061  uint length= strlen(script);
2062  uint count= 0; /* We know that there is always one */
2063 
2064  for (tmp= *sptr= (statement *)my_malloc(sizeof(statement),
2065  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2066  (retstr= strchr(ptr, delm));
2067  tmp->next= (statement *)my_malloc(sizeof(statement),
2068  MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2069  tmp= tmp->next)
2070  {
2071  count++;
2072  tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE));
2073  tmp->length= (size_t)(retstr - ptr);
2074  ptr+= retstr - ptr + 1;
2075  if (isspace(*ptr))
2076  ptr++;
2077  }
2078 
2079  if (ptr != script+length)
2080  {
2081  tmp->string= my_strndup(ptr, (uint)((script + length) - ptr),
2082  MYF(MY_FAE));
2083  tmp->length= (size_t)((script + length) - ptr);
2084  count++;
2085  }
2086 
2087  return count;
2088 }
2089 
2090 
2091 uint
2092 parse_comma(const char *string, uint **range)
2093 {
2094  uint count= 1,x; /* We know that there is always one */
2095  char *retstr;
2096  char *ptr= (char *)string;
2097  uint *nptr;
2098 
2099  for (;*ptr; ptr++)
2100  if (*ptr == ',') count++;
2101 
2102  /* One extra spot for the NULL */
2103  nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1),
2104  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2105 
2106  ptr= (char *)string;
2107  x= 0;
2108  while ((retstr= strchr(ptr,',')))
2109  {
2110  nptr[x++]= atoi(ptr);
2111  ptr+= retstr - ptr + 1;
2112  }
2113  nptr[x++]= atoi(ptr);
2114 
2115  return count;
2116 }
2117 
2118 void
2119 print_conclusions(conclusions *con)
2120 {
2121  printf("Benchmark\n");
2122  if (con->engine)
2123  printf("\tRunning for engine %s\n", con->engine);
2124  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2125  con->avg_timing / 1000, con->avg_timing % 1000);
2126  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2127  con->min_timing / 1000, con->min_timing % 1000);
2128  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2129  con->max_timing / 1000, con->max_timing % 1000);
2130  printf("\tNumber of clients running queries: %d\n", con->users);
2131  printf("\tAverage number of queries per client: %llu\n", con->avg_rows);
2132  printf("\n");
2133 }
2134 
2135 void
2136 print_conclusions_csv(conclusions *con)
2137 {
2138  char buffer[HUGE_STRING_LENGTH];
2139  const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query";
2140  snprintf(buffer, HUGE_STRING_LENGTH,
2141  "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
2142  con->engine ? con->engine : "", /* Storage engine we ran against */
2143  ptr, /* Load type */
2144  con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2145  con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2146  con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2147  con->users, /* Children used */
2148  con->avg_rows /* Queries run */
2149  );
2150  my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2151 }
2152 
2153 void
2154 generate_stats(conclusions *con, option_string *eng, stats *sptr)
2155 {
2156  stats *ptr;
2157  unsigned int x;
2158 
2159  con->min_timing= sptr->timing;
2160  con->max_timing= sptr->timing;
2161  con->min_rows= sptr->rows;
2162  con->max_rows= sptr->rows;
2163 
2164  /* At the moment we assume uniform */
2165  con->users= sptr->users;
2166  con->avg_rows= sptr->rows;
2167 
2168  /* With no next, we know it is the last element that was malloced */
2169  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2170  {
2171  con->avg_timing+= ptr->timing;
2172 
2173  if (ptr->timing > con->max_timing)
2174  con->max_timing= ptr->timing;
2175  if (ptr->timing < con->min_timing)
2176  con->min_timing= ptr->timing;
2177  }
2178  con->avg_timing= con->avg_timing/iterations;
2179 
2180  if (eng && eng->string)
2181  con->engine= eng->string;
2182  else
2183  con->engine= NULL;
2184 }
2185 
2186 void
2187 option_cleanup(option_string *stmt)
2188 {
2189  option_string *ptr, *nptr;
2190  if (!stmt)
2191  return;
2192 
2193  for (ptr= stmt; ptr; ptr= nptr)
2194  {
2195  nptr= ptr->next;
2196  my_free(ptr->string);
2197  my_free(ptr->option);
2198  my_free(ptr);
2199  }
2200 }
2201 
2202 void
2203 statement_cleanup(statement *stmt)
2204 {
2205  statement *ptr, *nptr;
2206  if (!stmt)
2207  return;
2208 
2209  for (ptr= stmt; ptr; ptr= nptr)
2210  {
2211  nptr= ptr->next;
2212  my_free(ptr->string);
2213  my_free(ptr);
2214  }
2215 }
2216 
2217 
2218 int
2219 slap_connect(MYSQL *mysql)
2220 {
2221  /* Connect to server */
2222  static ulong connection_retry_sleep= 100000; /* Microseconds */
2223  int x, connect_error= 1;
2224  for (x= 0; x < 10; x++)
2225  {
2226  if (mysql_real_connect(mysql, host, user, opt_password,
2227  create_schema_string,
2228  opt_mysql_port,
2229  opt_mysql_unix_port,
2230  connect_flags))
2231  {
2232  /* Connect suceeded */
2233  connect_error= 0;
2234  break;
2235  }
2236  my_sleep(connection_retry_sleep);
2237  }
2238  if (connect_error)
2239  {
2240  fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2241  my_progname, mysql_errno(mysql), mysql_error(mysql));
2242  return 1;
2243  }
2244 
2245  return 0;
2246 }