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