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