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/mariadb-slap.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(PSI_NOT_INSTRUMENTED,
437 sizeof(stats) * iterations, 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(const struct my_option * opt,const char * argument,const char * filename)729 get_one_option(const struct my_option *opt, const char *argument,
730 const char *filename __attribute__((unused)))
731 {
732 DBUG_ENTER("get_one_option");
733 switch(opt->id) {
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 /*
743 One should not really change the argument, but we make an
744 exception for passwords
745 */
746 char *start= (char*) argument;
747 my_free(opt_password);
748 opt_password= my_strdup(PSI_NOT_INSTRUMENTED, argument,MYF(MY_FAE));
749 while (*argument)
750 *(char*) argument++= 'x'; /* Destroy argument */
751 if (*start)
752 start[1]= 0; /* Cut length of argument */
753 tty_password= 0;
754 }
755 else
756 tty_password= 1;
757 break;
758 case 'W':
759 #ifdef __WIN__
760 opt_protocol= MYSQL_PROTOCOL_PIPE;
761 #endif
762 break;
763 case OPT_MYSQL_PROTOCOL:
764 if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
765 opt->name)) <= 0)
766 {
767 sf_leaking_memory= 1; /* no memory leak reports here */
768 exit(1);
769 }
770 break;
771 case '#':
772 DBUG_PUSH(argument ? argument : default_dbug_option);
773 debug_check_flag= 1;
774 break;
775 case OPT_CHARSETS_DIR:
776 strmake_buf(mysql_charsets_dir, argument);
777 charsets_dir = mysql_charsets_dir;
778 break;
779 case OPT_SLAP_CSV:
780 if (!argument)
781 argument= (char *)"-"; /* use stdout */
782 opt_csv_str= argument;
783 break;
784 #include <sslopt-case.h>
785 case 'V':
786 print_version();
787 exit(0);
788 break;
789 case '?':
790 case 'I': /* Info */
791 usage();
792 exit(0);
793 }
794 DBUG_RETURN(0);
795 }
796
797
798 uint
get_random_string(char * buf)799 get_random_string(char *buf)
800 {
801 char *buf_ptr= buf;
802 int x;
803 DBUG_ENTER("get_random_string");
804 for (x= RAND_STRING_SIZE; x > 0; x--)
805 *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
806 DBUG_RETURN((uint)(buf_ptr - buf));
807 }
808
809
810 /*
811 build_table_string
812
813 This function builds a create table query if the user opts to not supply
814 a file or string containing a create table statement
815 */
816 static statement *
build_table_string(void)817 build_table_string(void)
818 {
819 char buf[HUGE_STRING_LENGTH];
820 unsigned int col_count;
821 statement *ptr;
822 DYNAMIC_STRING table_string;
823 DBUG_ENTER("build_table_string");
824
825 DBUG_PRINT("info", ("num int cols %u num char cols %u",
826 num_int_cols, num_char_cols));
827
828 init_dynamic_string(&table_string, "", 1024, 1024);
829
830 dynstr_append(&table_string, "CREATE TABLE `t1` (");
831
832 if (auto_generate_sql_autoincrement)
833 {
834 dynstr_append(&table_string, "id serial");
835
836 if (num_int_cols || num_char_cols)
837 dynstr_append(&table_string, ",");
838 }
839
840 if (auto_generate_sql_guid_primary)
841 {
842 dynstr_append(&table_string, "id varchar(36) primary key");
843
844 if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
845 dynstr_append(&table_string, ",");
846 }
847
848 if (auto_generate_sql_secondary_indexes)
849 {
850 unsigned int count;
851
852 for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
853 {
854 if (count) /* Except for the first pass we add a comma */
855 dynstr_append(&table_string, ",");
856
857 if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(36) unique key", count)
858 > HUGE_STRING_LENGTH)
859 {
860 fprintf(stderr, "Memory Allocation error in create table\n");
861 exit(1);
862 }
863 dynstr_append(&table_string, buf);
864 }
865
866 if (num_int_cols || num_char_cols)
867 dynstr_append(&table_string, ",");
868 }
869
870 if (num_int_cols)
871 for (col_count= 1; col_count <= num_int_cols; col_count++)
872 {
873 if (num_int_cols_index)
874 {
875 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)",
876 col_count, col_count) > HUGE_STRING_LENGTH)
877 {
878 fprintf(stderr, "Memory Allocation error in create table\n");
879 exit(1);
880 }
881 }
882 else
883 {
884 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count)
885 > HUGE_STRING_LENGTH)
886 {
887 fprintf(stderr, "Memory Allocation error in create table\n");
888 exit(1);
889 }
890 }
891 dynstr_append(&table_string, buf);
892
893 if (col_count < num_int_cols || num_char_cols > 0)
894 dynstr_append(&table_string, ",");
895 }
896
897 if (num_char_cols)
898 for (col_count= 1; col_count <= num_char_cols; col_count++)
899 {
900 if (num_char_cols_index)
901 {
902 if (snprintf(buf, HUGE_STRING_LENGTH,
903 "charcol%d VARCHAR(128), INDEX(charcol%d) ",
904 col_count, col_count) > HUGE_STRING_LENGTH)
905 {
906 fprintf(stderr, "Memory Allocation error in creating table\n");
907 exit(1);
908 }
909 }
910 else
911 {
912 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
913 col_count) > HUGE_STRING_LENGTH)
914 {
915 fprintf(stderr, "Memory Allocation error in creating table\n");
916 exit(1);
917 }
918 }
919 dynstr_append(&table_string, buf);
920
921 if (col_count < num_char_cols)
922 dynstr_append(&table_string, ",");
923 }
924
925 dynstr_append(&table_string, ")");
926 ptr= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
927 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
928 ptr->string = (char *)my_malloc(PSI_NOT_INSTRUMENTED, table_string.length+1,
929 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
930 ptr->length= table_string.length+1;
931 ptr->type= CREATE_TABLE_TYPE;
932 strmov(ptr->string, table_string.str);
933 dynstr_free(&table_string);
934 DBUG_RETURN(ptr);
935 }
936
937 /*
938 build_update_string()
939
940 This function builds insert statements when the user opts to not supply
941 an insert file or string containing insert data
942 */
943 static statement *
build_update_string(void)944 build_update_string(void)
945 {
946 char buf[HUGE_STRING_LENGTH];
947 unsigned int col_count;
948 statement *ptr;
949 DYNAMIC_STRING update_string;
950 DBUG_ENTER("build_update_string");
951
952 init_dynamic_string(&update_string, "", 1024, 1024);
953
954 dynstr_append(&update_string, "UPDATE t1 SET ");
955
956 if (num_int_cols)
957 for (col_count= 1; col_count <= num_int_cols; col_count++)
958 {
959 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
960 random()) > HUGE_STRING_LENGTH)
961 {
962 fprintf(stderr, "Memory Allocation error in creating update\n");
963 exit(1);
964 }
965 dynstr_append(&update_string, buf);
966
967 if (col_count < num_int_cols || num_char_cols > 0)
968 dynstr_append_mem(&update_string, ",", 1);
969 }
970
971 if (num_char_cols)
972 for (col_count= 1; col_count <= num_char_cols; col_count++)
973 {
974 char rand_buffer[RAND_STRING_SIZE];
975 int buf_len= get_random_string(rand_buffer);
976
977 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
978 buf_len, rand_buffer)
979 > HUGE_STRING_LENGTH)
980 {
981 fprintf(stderr, "Memory Allocation error in creating update\n");
982 exit(1);
983 }
984 dynstr_append(&update_string, buf);
985
986 if (col_count < num_char_cols)
987 dynstr_append_mem(&update_string, ",", 1);
988 }
989
990 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
991 dynstr_append(&update_string, " WHERE id = ");
992
993
994 ptr= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
995 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
996
997 ptr->string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, update_string.length + 1,
998 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
999 ptr->length= update_string.length+1;
1000 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1001 ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
1002 else
1003 ptr->type= UPDATE_TYPE;
1004
1005 strmov(ptr->string, update_string.str);
1006 dynstr_free(&update_string);
1007 DBUG_RETURN(ptr);
1008 }
1009
1010
1011 /*
1012 build_insert_string()
1013
1014 This function builds insert statements when the user opts to not supply
1015 an insert file or string containing insert data
1016 */
1017 static statement *
build_insert_string(void)1018 build_insert_string(void)
1019 {
1020 char buf[HUGE_STRING_LENGTH];
1021 unsigned int col_count;
1022 statement *ptr;
1023 DYNAMIC_STRING insert_string;
1024 DBUG_ENTER("build_insert_string");
1025
1026 init_dynamic_string(&insert_string, "", 1024, 1024);
1027
1028 dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
1029
1030 if (auto_generate_sql_autoincrement)
1031 {
1032 dynstr_append(&insert_string, "NULL");
1033
1034 if (num_int_cols || num_char_cols)
1035 dynstr_append(&insert_string, ",");
1036 }
1037
1038 if (auto_generate_sql_guid_primary)
1039 {
1040 dynstr_append(&insert_string, "uuid()");
1041
1042 if (num_int_cols || num_char_cols)
1043 dynstr_append(&insert_string, ",");
1044 }
1045
1046 if (auto_generate_sql_secondary_indexes)
1047 {
1048 unsigned int count;
1049
1050 for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1051 {
1052 if (count) /* Except for the first pass we add a comma */
1053 dynstr_append(&insert_string, ",");
1054
1055 dynstr_append(&insert_string, "uuid()");
1056 }
1057
1058 if (num_int_cols || num_char_cols)
1059 dynstr_append(&insert_string, ",");
1060 }
1061
1062 if (num_int_cols)
1063 for (col_count= 1; col_count <= num_int_cols; col_count++)
1064 {
1065 if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1066 {
1067 fprintf(stderr, "Memory Allocation error in creating insert\n");
1068 exit(1);
1069 }
1070 dynstr_append(&insert_string, buf);
1071
1072 if (col_count < num_int_cols || num_char_cols > 0)
1073 dynstr_append_mem(&insert_string, ",", 1);
1074 }
1075
1076 if (num_char_cols)
1077 for (col_count= 1; col_count <= num_char_cols; col_count++)
1078 {
1079 int buf_len= get_random_string(buf);
1080 dynstr_append_mem(&insert_string, "'", 1);
1081 dynstr_append_mem(&insert_string, buf, buf_len);
1082 dynstr_append_mem(&insert_string, "'", 1);
1083
1084 if (col_count < num_char_cols)
1085 dynstr_append_mem(&insert_string, ",", 1);
1086 }
1087
1088 dynstr_append_mem(&insert_string, ")", 1);
1089
1090 ptr= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
1091 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1092 ptr->string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, insert_string.length + 1,
1093 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1094 ptr->length= insert_string.length+1;
1095 ptr->type= INSERT_TYPE;
1096 strmov(ptr->string, insert_string.str);
1097 dynstr_free(&insert_string);
1098 DBUG_RETURN(ptr);
1099 }
1100
1101
1102 /*
1103 build_select_string()
1104
1105 This function builds a query if the user opts to not supply a query
1106 statement or file containing a query statement
1107 */
1108 static statement *
build_select_string(my_bool key)1109 build_select_string(my_bool key)
1110 {
1111 char buf[HUGE_STRING_LENGTH];
1112 unsigned int col_count;
1113 statement *ptr;
1114 static DYNAMIC_STRING query_string;
1115 DBUG_ENTER("build_select_string");
1116
1117 init_dynamic_string(&query_string, "", 1024, 1024);
1118
1119 dynstr_append_mem(&query_string, "SELECT ", 7);
1120 for (col_count= 1; col_count <= num_int_cols; col_count++)
1121 {
1122 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1123 > HUGE_STRING_LENGTH)
1124 {
1125 fprintf(stderr, "Memory Allocation error in creating select\n");
1126 exit(1);
1127 }
1128 dynstr_append(&query_string, buf);
1129
1130 if (col_count < num_int_cols || num_char_cols > 0)
1131 dynstr_append_mem(&query_string, ",", 1);
1132
1133 }
1134 for (col_count= 1; col_count <= num_char_cols; col_count++)
1135 {
1136 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1137 > HUGE_STRING_LENGTH)
1138 {
1139 fprintf(stderr, "Memory Allocation error in creating select\n");
1140 exit(1);
1141 }
1142 dynstr_append(&query_string, buf);
1143
1144 if (col_count < num_char_cols)
1145 dynstr_append_mem(&query_string, ",", 1);
1146
1147 }
1148 dynstr_append(&query_string, " FROM t1");
1149
1150 if ((key) &&
1151 (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1152 dynstr_append(&query_string, " WHERE id = ");
1153
1154 ptr= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
1155 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1156 ptr->string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, query_string.length + 1,
1157 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1158 ptr->length= query_string.length+1;
1159 if ((key) &&
1160 (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1161 ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1162 else
1163 ptr->type= SELECT_TYPE;
1164
1165 strmov(ptr->string, query_string.str);
1166 dynstr_free(&query_string);
1167 DBUG_RETURN(ptr);
1168 }
1169
1170 static int
get_options(int * argc,char *** argv)1171 get_options(int *argc,char ***argv)
1172 {
1173 int ho_error;
1174 char *tmp_string;
1175 MY_STAT sbuf; /* Stat information for the data file */
1176
1177 DBUG_ENTER("get_options");
1178 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1179 exit(ho_error);
1180 if (debug_info_flag)
1181 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1182 if (debug_check_flag)
1183 my_end_arg= MY_CHECK_ERROR;
1184
1185 /*
1186 If something is created and --no-drop is not specified, we drop the
1187 schema.
1188 */
1189 if (!opt_no_drop && (create_string || auto_generate_sql))
1190 opt_preserve= FALSE;
1191
1192 if (auto_generate_sql && (create_string || user_supplied_query))
1193 {
1194 fprintf(stderr,
1195 "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1196 my_progname);
1197 exit(1);
1198 }
1199
1200 if (auto_generate_sql && auto_generate_sql_guid_primary &&
1201 auto_generate_sql_autoincrement)
1202 {
1203 fprintf(stderr,
1204 "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1205 my_progname);
1206 exit(1);
1207 }
1208
1209 /*
1210 We are testing to make sure that if someone specified a key search
1211 that we actually added a key!
1212 */
1213 if (auto_generate_sql && auto_generate_sql_type[0] == 'k')
1214 if ( auto_generate_sql_autoincrement == FALSE &&
1215 auto_generate_sql_guid_primary == FALSE)
1216 {
1217 fprintf(stderr,
1218 "%s: Can't perform key test without a primary key!\n",
1219 my_progname);
1220 exit(1);
1221 }
1222
1223 if (auto_generate_sql && num_of_query && auto_actual_queries)
1224 {
1225 fprintf(stderr,
1226 "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1227 my_progname);
1228 exit(1);
1229 }
1230
1231 parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1232
1233 if (opt_csv_str)
1234 {
1235 opt_silent= TRUE;
1236
1237 if (opt_csv_str[0] == '-')
1238 {
1239 csv_file= my_fileno(stdout);
1240 }
1241 else
1242 {
1243 if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1244 == -1)
1245 {
1246 fprintf(stderr,"%s: Could not open csv file: %sn\n",
1247 my_progname, opt_csv_str);
1248 exit(1);
1249 }
1250 }
1251 }
1252
1253 if (opt_only_print)
1254 opt_silent= TRUE;
1255
1256 if (num_int_cols_opt)
1257 {
1258 option_string *str;
1259 if(parse_option(num_int_cols_opt, &str, ',') == -1)
1260 {
1261 fprintf(stderr, "Invalid value specified for the option "
1262 "'number-int-cols'\n");
1263 option_cleanup(str);
1264 return 1;
1265 }
1266 num_int_cols= atoi(str->string);
1267 if (str->option)
1268 num_int_cols_index= atoi(str->option);
1269
1270 option_cleanup(str);
1271 }
1272
1273 if (num_char_cols_opt)
1274 {
1275 option_string *str;
1276 if(parse_option(num_char_cols_opt, &str, ',') == -1)
1277 {
1278 fprintf(stderr, "Invalid value specified for the option "
1279 "'number-char-cols'\n");
1280 option_cleanup(str);
1281 return 1;
1282 }
1283 num_char_cols= atoi(str->string);
1284 if (str->option)
1285 num_char_cols_index= atoi(str->option);
1286 else
1287 num_char_cols_index= 0;
1288
1289 option_cleanup(str);
1290 }
1291
1292
1293 if (auto_generate_sql)
1294 {
1295 unsigned long long x= 0;
1296 statement *ptr_statement;
1297
1298 if (verbose >= 2)
1299 printf("Building Create Statements for Auto\n");
1300
1301 create_statements= build_table_string();
1302 /*
1303 Pre-populate table
1304 */
1305 for (ptr_statement= create_statements, x= 0;
1306 x < auto_generate_sql_unique_write_number;
1307 x++, ptr_statement= ptr_statement->next)
1308 {
1309 ptr_statement->next= build_insert_string();
1310 }
1311
1312 if (verbose >= 2)
1313 printf("Building Query Statements for Auto\n");
1314
1315 if (auto_generate_sql_type[0] == 'r')
1316 {
1317 if (verbose >= 2)
1318 printf("Generating SELECT Statements for Auto\n");
1319
1320 query_statements= build_select_string(FALSE);
1321 for (ptr_statement= query_statements, x= 0;
1322 x < auto_generate_sql_unique_query_number;
1323 x++, ptr_statement= ptr_statement->next)
1324 {
1325 ptr_statement->next= build_select_string(FALSE);
1326 }
1327 }
1328 else if (auto_generate_sql_type[0] == 'k')
1329 {
1330 if (verbose >= 2)
1331 printf("Generating SELECT for keys Statements for Auto\n");
1332
1333 query_statements= build_select_string(TRUE);
1334 for (ptr_statement= query_statements, x= 0;
1335 x < auto_generate_sql_unique_query_number;
1336 x++, ptr_statement= ptr_statement->next)
1337 {
1338 ptr_statement->next= build_select_string(TRUE);
1339 }
1340 }
1341 else if (auto_generate_sql_type[0] == 'w')
1342 {
1343 /*
1344 We generate a number of strings in case the engine is
1345 Archive (since strings which were identical one after another
1346 would be too easily optimized).
1347 */
1348 if (verbose >= 2)
1349 printf("Generating INSERT Statements for Auto\n");
1350 query_statements= build_insert_string();
1351 for (ptr_statement= query_statements, x= 0;
1352 x < auto_generate_sql_unique_query_number;
1353 x++, ptr_statement= ptr_statement->next)
1354 {
1355 ptr_statement->next= build_insert_string();
1356 }
1357 }
1358 else if (auto_generate_sql_type[0] == 'u')
1359 {
1360 query_statements= build_update_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_update_string();
1366 }
1367 }
1368 else /* Mixed mode is default */
1369 {
1370 int coin= 0;
1371
1372 query_statements= build_insert_string();
1373 /*
1374 This logic should be extended to do a more mixed load,
1375 at the moment it results in "every other".
1376 */
1377 for (ptr_statement= query_statements, x= 0;
1378 x < auto_generate_sql_unique_query_number;
1379 x++, ptr_statement= ptr_statement->next)
1380 {
1381 if (coin)
1382 {
1383 ptr_statement->next= build_insert_string();
1384 coin= 0;
1385 }
1386 else
1387 {
1388 ptr_statement->next= build_select_string(TRUE);
1389 coin= 1;
1390 }
1391 }
1392 }
1393 }
1394 else
1395 {
1396 if (create_string && my_stat(create_string, &sbuf, MYF(0)))
1397 {
1398 File data_file;
1399 if (!MY_S_ISREG(sbuf.st_mode))
1400 {
1401 fprintf(stderr,"%s: Create file was not a regular file\n",
1402 my_progname);
1403 exit(1);
1404 }
1405 if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1406 {
1407 fprintf(stderr,"%s: Could not open create file\n", my_progname);
1408 exit(1);
1409 }
1410 tmp_string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, (size_t)sbuf.st_size + 1,
1411 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1412 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1413 tmp_string[sbuf.st_size]= '\0';
1414 my_close(data_file,MYF(0));
1415 parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1416 my_free(tmp_string);
1417 }
1418 else if (create_string)
1419 {
1420 parse_delimiter(create_string, &create_statements, delimiter[0]);
1421 }
1422
1423 if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0)))
1424 {
1425 File data_file;
1426 if (!MY_S_ISREG(sbuf.st_mode))
1427 {
1428 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1429 my_progname);
1430 exit(1);
1431 }
1432 if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1433 {
1434 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1435 exit(1);
1436 }
1437 tmp_string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, (size_t)sbuf.st_size + 1,
1438 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1439 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1440 tmp_string[sbuf.st_size]= '\0';
1441 my_close(data_file,MYF(0));
1442 if (user_supplied_query)
1443 actual_queries= parse_delimiter(tmp_string, &query_statements,
1444 delimiter[0]);
1445 my_free(tmp_string);
1446 }
1447 else if (user_supplied_query)
1448 {
1449 actual_queries= parse_delimiter(user_supplied_query, &query_statements,
1450 delimiter[0]);
1451 }
1452 }
1453
1454 if (user_supplied_pre_statements && my_stat(user_supplied_pre_statements, &sbuf, MYF(0)))
1455 {
1456 File data_file;
1457 if (!MY_S_ISREG(sbuf.st_mode))
1458 {
1459 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1460 my_progname);
1461 exit(1);
1462 }
1463 if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1464 {
1465 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1466 exit(1);
1467 }
1468 tmp_string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, (size_t)sbuf.st_size + 1,
1469 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1470 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1471 tmp_string[sbuf.st_size]= '\0';
1472 my_close(data_file,MYF(0));
1473 if (user_supplied_pre_statements)
1474 (void)parse_delimiter(tmp_string, &pre_statements,
1475 delimiter[0]);
1476 my_free(tmp_string);
1477 }
1478 else if (user_supplied_pre_statements)
1479 {
1480 (void)parse_delimiter(user_supplied_pre_statements,
1481 &pre_statements,
1482 delimiter[0]);
1483 }
1484
1485 if (user_supplied_post_statements && my_stat(user_supplied_post_statements, &sbuf, MYF(0)))
1486 {
1487 File data_file;
1488 if (!MY_S_ISREG(sbuf.st_mode))
1489 {
1490 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1491 my_progname);
1492 exit(1);
1493 }
1494 if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1495 {
1496 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1497 exit(1);
1498 }
1499 tmp_string= (char *)my_malloc(PSI_NOT_INSTRUMENTED, (size_t)sbuf.st_size + 1,
1500 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1501 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1502 tmp_string[sbuf.st_size]= '\0';
1503 my_close(data_file,MYF(0));
1504 if (user_supplied_post_statements)
1505 (void)parse_delimiter(tmp_string, &post_statements,
1506 delimiter[0]);
1507 my_free(tmp_string);
1508 }
1509 else if (user_supplied_post_statements)
1510 {
1511 (void)parse_delimiter(user_supplied_post_statements, &post_statements,
1512 delimiter[0]);
1513 }
1514
1515 if (verbose >= 2)
1516 printf("Parsing engines to use.\n");
1517
1518 if (default_engine)
1519 {
1520 if(parse_option(default_engine, &engine_options, ',') == -1)
1521 {
1522 fprintf(stderr, "Invalid value specified for the option 'engine'\n");
1523 return 1;
1524 }
1525 }
1526
1527 if (tty_password)
1528 opt_password= get_tty_password(NullS);
1529
1530 DBUG_RETURN(0);
1531 }
1532
1533
run_query(MYSQL * mysql,const char * query,size_t len)1534 static int run_query(MYSQL *mysql, const char *query, size_t len)
1535 {
1536 if (opt_only_print)
1537 {
1538 printf("%.*s;\n", (int)len, query);
1539 return 0;
1540 }
1541
1542 if (verbose >= 3)
1543 printf("%.*s;\n", (int)len, query);
1544
1545 return mysql_real_query(mysql, query, (ulong)len);
1546 }
1547
1548
1549 static int
generate_primary_key_list(MYSQL * mysql,option_string * engine_stmt)1550 generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1551 {
1552 MYSQL_RES *result;
1553 MYSQL_ROW row;
1554 unsigned long long counter;
1555 DBUG_ENTER("generate_primary_key_list");
1556
1557 /*
1558 Blackhole is a special case, this allows us to test the upper end
1559 of the server during load runs.
1560 */
1561 if (opt_only_print || (engine_stmt &&
1562 strstr(engine_stmt->string, "blackhole")))
1563 {
1564 primary_keys_number_of= 1;
1565 primary_keys= (char **)my_malloc(PSI_NOT_INSTRUMENTED,
1566 (size_t)(sizeof(char *) * primary_keys_number_of),
1567 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1568 /* Yes, we strdup a const string to simplify the interface */
1569 primary_keys[0]= my_strdup(PSI_NOT_INSTRUMENTED, "796c4422-1d94-102a-9d6d-00e0812d", MYF(0));
1570 }
1571 else
1572 {
1573 if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1574 {
1575 fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1576 mysql_error(mysql));
1577 exit(1);
1578 }
1579
1580 if (!(result= mysql_store_result(mysql)))
1581 {
1582 fprintf(stderr, "%s: Error when storing result: %d %s\n",
1583 my_progname, mysql_errno(mysql), mysql_error(mysql));
1584 exit(1);
1585 }
1586 primary_keys_number_of= mysql_num_rows(result);
1587
1588 /* So why check this? Blackhole :) */
1589 if (primary_keys_number_of)
1590 {
1591 /*
1592 We create the structure and loop and create the items.
1593 */
1594 primary_keys= (char **)my_malloc(PSI_NOT_INSTRUMENTED,
1595 (size_t)(sizeof(char *) * primary_keys_number_of),
1596 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1597 row= mysql_fetch_row(result);
1598 for (counter= 0; counter < primary_keys_number_of;
1599 counter++, row= mysql_fetch_row(result))
1600 primary_keys[counter]= my_strdup(PSI_NOT_INSTRUMENTED, row[0], MYF(0));
1601 }
1602
1603 mysql_free_result(result);
1604 }
1605
1606 DBUG_RETURN(0);
1607 }
1608
1609 static int
drop_primary_key_list(void)1610 drop_primary_key_list(void)
1611 {
1612 unsigned long long counter;
1613
1614 if (primary_keys_number_of)
1615 {
1616 for (counter= 0; counter < primary_keys_number_of; counter++)
1617 my_free(primary_keys[counter]);
1618
1619 my_free(primary_keys);
1620 }
1621
1622 return 0;
1623 }
1624
1625 static int
create_schema(MYSQL * mysql,const char * db,statement * stmt,option_string * engine_stmt)1626 create_schema(MYSQL *mysql, const char *db, statement *stmt,
1627 option_string *engine_stmt)
1628 {
1629 char query[HUGE_STRING_LENGTH];
1630 statement *ptr;
1631 statement *after_create;
1632 int len;
1633 ulonglong count;
1634 DBUG_ENTER("create_schema");
1635
1636 len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1637
1638 if (verbose >= 2)
1639 printf("Loading Pre-data\n");
1640
1641 if (run_query(mysql, query, len))
1642 {
1643 fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1644 mysql_error(mysql));
1645 exit(1);
1646 }
1647
1648 if (opt_only_print)
1649 {
1650 printf("use %s;\n", db);
1651 }
1652 else
1653 {
1654 if (verbose >= 3)
1655 printf("%s;\n", query);
1656
1657 if (mysql_select_db(mysql, db))
1658 {
1659 fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1660 mysql_error(mysql));
1661 exit(1);
1662 }
1663 }
1664
1665 count= 0;
1666 after_create= stmt;
1667
1668 limit_not_met:
1669 for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1670 {
1671 if (auto_generate_sql && ( auto_generate_sql_number == count))
1672 break;
1673
1674 if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1675 {
1676 char buffer[HUGE_STRING_LENGTH];
1677
1678 snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s %s",
1679 ptr->string, engine_stmt->string, engine_stmt->option);
1680 if (run_query(mysql, buffer, strlen(buffer)))
1681 {
1682 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1683 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1684 exit(1);
1685 }
1686 }
1687 else if (engine_stmt && engine_stmt->string && ptr->type == CREATE_TABLE_TYPE)
1688 {
1689 char buffer[HUGE_STRING_LENGTH];
1690
1691 snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s",
1692 ptr->string, engine_stmt->string);
1693 if (run_query(mysql, buffer, strlen(buffer)))
1694 {
1695 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1696 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1697 exit(1);
1698 }
1699 }
1700 else
1701 {
1702 if (run_query(mysql, ptr->string, ptr->length))
1703 {
1704 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1705 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1706 exit(1);
1707 }
1708 }
1709 }
1710
1711 if (auto_generate_sql && (auto_generate_sql_number > count ))
1712 {
1713 /* Special case for auto create, we don't want to create tables twice */
1714 after_create= stmt->next;
1715 goto limit_not_met;
1716 }
1717
1718 DBUG_RETURN(0);
1719 }
1720
1721 static int
drop_schema(MYSQL * mysql,const char * db)1722 drop_schema(MYSQL *mysql, const char *db)
1723 {
1724 char query[HUGE_STRING_LENGTH];
1725 int len;
1726
1727 DBUG_ENTER("drop_schema");
1728 len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1729
1730 if (run_query(mysql, query, len))
1731 {
1732 fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1733 my_progname, db, mysql_error(mysql));
1734 exit(1);
1735 }
1736
1737
1738
1739 DBUG_RETURN(0);
1740 }
1741
1742 static int
run_statements(MYSQL * mysql,statement * stmt)1743 run_statements(MYSQL *mysql, statement *stmt)
1744 {
1745 statement *ptr;
1746 MYSQL_RES *result;
1747 DBUG_ENTER("run_statements");
1748
1749 for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1750 {
1751 if (run_query(mysql, ptr->string, ptr->length))
1752 {
1753 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1754 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1755 exit(1);
1756 }
1757 if (mysql_field_count(mysql))
1758 {
1759 result= mysql_store_result(mysql);
1760 mysql_free_result(result);
1761 }
1762 }
1763
1764 DBUG_RETURN(0);
1765 }
1766
1767 static int
run_scheduler(stats * sptr,statement * stmts,uint concur,ulonglong limit)1768 run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit)
1769 {
1770 uint x;
1771 struct timeval start_time, end_time;
1772 thread_context con;
1773 pthread_t mainthread; /* Thread descriptor */
1774 pthread_attr_t attr; /* Thread attributes */
1775 DBUG_ENTER("run_scheduler");
1776
1777 con.stmt= stmts;
1778 con.limit= limit;
1779
1780 pthread_attr_init(&attr);
1781 pthread_attr_setdetachstate(&attr,
1782 PTHREAD_CREATE_DETACHED);
1783
1784 pthread_mutex_lock(&counter_mutex);
1785 thread_counter= 0;
1786
1787 pthread_mutex_lock(&sleeper_mutex);
1788 master_wakeup= 1;
1789 pthread_mutex_unlock(&sleeper_mutex);
1790 for (x= 0; x < concur; x++)
1791 {
1792 /* now you create the thread */
1793 if (pthread_create(&mainthread, &attr, run_task,
1794 (void *)&con) != 0)
1795 {
1796 fprintf(stderr,"%s: Could not create thread\n",
1797 my_progname);
1798 exit(0);
1799 }
1800 thread_counter++;
1801 }
1802 pthread_mutex_unlock(&counter_mutex);
1803 pthread_attr_destroy(&attr);
1804
1805 pthread_mutex_lock(&sleeper_mutex);
1806 master_wakeup= 0;
1807 pthread_cond_broadcast(&sleep_threshhold);
1808 pthread_mutex_unlock(&sleeper_mutex);
1809
1810 gettimeofday(&start_time, NULL);
1811
1812 /*
1813 We loop until we know that all children have cleaned up.
1814 */
1815 pthread_mutex_lock(&counter_mutex);
1816 while (thread_counter)
1817 {
1818 struct timespec abstime;
1819
1820 set_timespec(abstime, 3);
1821 pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1822 }
1823 pthread_mutex_unlock(&counter_mutex);
1824
1825 gettimeofday(&end_time, NULL);
1826
1827
1828 sptr->timing= timedif(end_time, start_time);
1829 sptr->users= concur;
1830 sptr->rows= limit;
1831
1832 DBUG_RETURN(0);
1833 }
1834
1835
run_task(void * p)1836 pthread_handler_t run_task(void *p)
1837 {
1838 ulonglong counter= 0, queries;
1839 ulonglong detach_counter;
1840 unsigned int commit_counter;
1841 MYSQL *mysql;
1842 MYSQL_RES *result;
1843 MYSQL_ROW row;
1844 statement *ptr;
1845 thread_context *con= (thread_context *)p;
1846
1847 DBUG_ENTER("run_task");
1848 DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : ""));
1849
1850 pthread_mutex_lock(&sleeper_mutex);
1851 while (master_wakeup)
1852 {
1853 pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
1854 }
1855 pthread_mutex_unlock(&sleeper_mutex);
1856
1857 if (mysql_thread_init())
1858 {
1859 fprintf(stderr,"%s: mysql_thread_init() failed\n", my_progname);
1860 exit(0);
1861 }
1862
1863 if (!(mysql= mysql_init(NULL)))
1864 {
1865 fprintf(stderr,"%s: mysql_init() failed\n", my_progname);
1866 mysql_thread_end();
1867 exit(0);
1868 }
1869
1870 set_mysql_connect_options(mysql);
1871
1872 DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user));
1873
1874 if (!opt_only_print)
1875 {
1876 if (slap_connect(mysql))
1877 goto end;
1878 }
1879
1880 DBUG_PRINT("info", ("connected."));
1881 if (verbose >= 3)
1882 printf("connected!\n");
1883 queries= 0;
1884
1885 commit_counter= 0;
1886 if (commit_rate)
1887 run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
1888
1889 limit_not_met:
1890 for (ptr= con->stmt, detach_counter= 0;
1891 ptr && ptr->length;
1892 ptr= ptr->next, detach_counter++)
1893 {
1894 if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
1895 {
1896 mysql_close(mysql);
1897
1898 if (!(mysql= mysql_init(NULL)))
1899 {
1900 fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1901 my_progname, mysql_error(mysql));
1902 exit(0);
1903 }
1904 if (slap_connect(mysql))
1905 goto end;
1906 }
1907
1908 /*
1909 We have to execute differently based on query type. This should become a function.
1910 */
1911 if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
1912 (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
1913 {
1914 int length;
1915 unsigned int key_val;
1916 char *key;
1917 char buffer[HUGE_STRING_LENGTH];
1918
1919 /*
1920 This should only happen if some sort of new engine was
1921 implemented that didn't properly handle UPDATEs.
1922
1923 Just in case someone runs this under an experimental engine we don't
1924 want a crash so the if() is placed here.
1925 */
1926 DBUG_ASSERT(primary_keys_number_of);
1927 if (primary_keys_number_of)
1928 {
1929 key_val= (unsigned int)(random() % primary_keys_number_of);
1930 key= primary_keys[key_val];
1931
1932 DBUG_ASSERT(key);
1933
1934 length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
1935 (int)ptr->length, ptr->string, key);
1936
1937 if (run_query(mysql, buffer, length))
1938 {
1939 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1940 my_progname, (uint)length, buffer, mysql_error(mysql));
1941 exit(0);
1942 }
1943 }
1944 }
1945 else
1946 {
1947 if (run_query(mysql, ptr->string, ptr->length))
1948 {
1949 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1950 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1951 exit(0);
1952 }
1953 }
1954
1955 do
1956 {
1957 if (mysql_field_count(mysql))
1958 {
1959 if (!(result= mysql_store_result(mysql)))
1960 fprintf(stderr, "%s: Error when storing result: %d %s\n",
1961 my_progname, mysql_errno(mysql), mysql_error(mysql));
1962 else
1963 {
1964 while ((row= mysql_fetch_row(result)))
1965 counter++;
1966 mysql_free_result(result);
1967 }
1968 }
1969 } while(mysql_next_result(mysql) == 0);
1970 queries++;
1971
1972 if (commit_rate && (++commit_counter == commit_rate))
1973 {
1974 commit_counter= 0;
1975 run_query(mysql, "COMMIT", strlen("COMMIT"));
1976 }
1977
1978 if (con->limit && queries == con->limit)
1979 goto end;
1980 }
1981
1982 if (con->limit && queries < con->limit)
1983 goto limit_not_met;
1984
1985 end:
1986 if (commit_rate)
1987 run_query(mysql, "COMMIT", strlen("COMMIT"));
1988
1989 mysql_close(mysql);
1990
1991 mysql_thread_end();
1992
1993 pthread_mutex_lock(&counter_mutex);
1994 thread_counter--;
1995 pthread_cond_signal(&count_threshhold);
1996 pthread_mutex_unlock(&counter_mutex);
1997
1998 DBUG_RETURN(0);
1999 }
2000
2001 int
parse_option(const char * origin,option_string ** stmt,char delm)2002 parse_option(const char *origin, option_string **stmt, char delm)
2003 {
2004 char *retstr;
2005 char *ptr= (char *)origin;
2006 option_string **sptr= stmt;
2007 option_string *tmp;
2008 size_t length= strlen(origin);
2009 uint count= 0; /* We know that there is always one */
2010
2011 for (tmp= *sptr= (option_string *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(option_string),
2012 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2013 (retstr= strchr(ptr, delm));
2014 tmp->next= (option_string *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(option_string),
2015 MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2016 tmp= tmp->next)
2017 {
2018 /*
2019 Initialize buffer, because otherwise an
2020 --engine=<storage_engine>:<option>,<eng1>,<eng2>
2021 will crash.
2022 */
2023 char buffer[HUGE_STRING_LENGTH]= "";
2024 char *buffer_ptr;
2025
2026 /*
2027 Return an error if the length of the any of the comma seprated value
2028 exceeds HUGE_STRING_LENGTH.
2029 */
2030 if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH)
2031 return -1;
2032
2033 count++;
2034 strncpy(buffer, ptr, (size_t)(retstr - ptr));
2035 /*
2036 Handle --engine=memory:max_row=200 cases, or more general speaking
2037 --engine=<storage_engine>:<options>, which will be translated to
2038 Engine = storage_engine option.
2039 */
2040 if ((buffer_ptr= strchr(buffer, ':')))
2041 {
2042 char *option_ptr;
2043
2044 tmp->length= (size_t)(buffer_ptr - buffer);
2045 tmp->string= my_strndup(PSI_NOT_INSTRUMENTED, ptr, (uint)tmp->length, MYF(MY_FAE));
2046
2047 option_ptr= ptr + 1 + tmp->length;
2048
2049 /* Move past the : and the first string */
2050 tmp->option_length= (size_t)(retstr - option_ptr);
2051 tmp->option= my_strndup(PSI_NOT_INSTRUMENTED, option_ptr, (uint)tmp->option_length,
2052 MYF(MY_FAE));
2053 }
2054 else
2055 {
2056 tmp->string= my_strndup(PSI_NOT_INSTRUMENTED, ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
2057 tmp->length= (size_t)(retstr - ptr);
2058 }
2059
2060 /* Skip delimiter delm */
2061 ptr+= retstr - ptr + 1;
2062 if (isspace(*ptr))
2063 ptr++;
2064
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(PSI_NOT_INSTRUMENTED, ptr, 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(PSI_NOT_INSTRUMENTED, option_ptr, tmp->option_length,
2091 MYF(MY_FAE));
2092 }
2093 else
2094 {
2095 tmp->length= strlen(ptr);
2096 tmp->string= my_strndup(PSI_NOT_INSTRUMENTED, 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 size_t length= strlen(script);
2114 uint count= 0; /* We know that there is always one */
2115
2116 for (tmp= *sptr= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
2117 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2118 (retstr= strchr(ptr, delm));
2119 tmp->next= (statement *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(statement),
2120 MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2121 tmp= tmp->next)
2122 {
2123 count++;
2124 tmp->string= my_strndup(PSI_NOT_INSTRUMENTED, 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(PSI_NOT_INSTRUMENTED, 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(PSI_NOT_INSTRUMENTED, 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
2193 snprintf(buffer, HUGE_STRING_LENGTH,
2194 "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
2195 con->engine ? con->engine : "", /* Storage engine we ran against */
2196 ptr, /* Load type */
2197 con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2198 con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2199 con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2200 con->users, /* Children used */
2201 con->avg_rows /* Queries run */
2202 );
2203 my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2204 }
2205
2206 void
generate_stats(conclusions * con,option_string * eng,stats * sptr)2207 generate_stats(conclusions *con, option_string *eng, stats *sptr)
2208 {
2209 stats *ptr;
2210 unsigned int x;
2211
2212 con->min_timing= sptr->timing;
2213 con->max_timing= sptr->timing;
2214 con->min_rows= sptr->rows;
2215 con->max_rows= sptr->rows;
2216
2217 /* At the moment we assume uniform */
2218 con->users= sptr->users;
2219 con->avg_rows= sptr->rows;
2220
2221 /* With no next, we know it is the last element that was malloced */
2222 for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2223 {
2224 con->avg_timing+= ptr->timing;
2225
2226 if (ptr->timing > con->max_timing)
2227 con->max_timing= ptr->timing;
2228 if (ptr->timing < con->min_timing)
2229 con->min_timing= ptr->timing;
2230 }
2231 con->avg_timing= con->avg_timing/iterations;
2232
2233 if (eng && eng->string)
2234 con->engine= eng->string;
2235 else
2236 con->engine= NULL;
2237 }
2238
2239 void
option_cleanup(option_string * stmt)2240 option_cleanup(option_string *stmt)
2241 {
2242 option_string *ptr, *nptr;
2243 if (!stmt)
2244 return;
2245
2246 for (ptr= stmt; ptr; ptr= nptr)
2247 {
2248 nptr= ptr->next;
2249 my_free(ptr->string);
2250 my_free(ptr->option);
2251 my_free(ptr);
2252 }
2253 }
2254
2255 void
statement_cleanup(statement * stmt)2256 statement_cleanup(statement *stmt)
2257 {
2258 statement *ptr, *nptr;
2259 if (!stmt)
2260 return;
2261
2262 for (ptr= stmt; ptr; ptr= nptr)
2263 {
2264 nptr= ptr->next;
2265 my_free(ptr->string);
2266 my_free(ptr);
2267 }
2268 }
2269
2270
2271 int
slap_connect(MYSQL * mysql)2272 slap_connect(MYSQL *mysql)
2273 {
2274 /* Connect to server */
2275 static ulong connection_retry_sleep= 100000; /* Microseconds */
2276 int x, connect_error= 1;
2277 for (x= 0; x < 10; x++)
2278 {
2279 set_mysql_connect_options(mysql);
2280 if (opt_init_command)
2281 mysql_options(mysql, MYSQL_INIT_COMMAND, opt_init_command);
2282 if (mysql_real_connect(mysql, host, user, opt_password,
2283 create_schema_string,
2284 opt_mysql_port,
2285 opt_mysql_unix_port,
2286 connect_flags))
2287 {
2288 /* Connect succeeded */
2289 connect_error= 0;
2290 break;
2291 }
2292 my_sleep(connection_retry_sleep);
2293 }
2294 if (connect_error)
2295 {
2296 fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2297 my_progname, mysql_errno(mysql), mysql_error(mysql));
2298 return 1;
2299 }
2300
2301 return 0;
2302 }
2303