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