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