The world's most popular open source database
00001 /* Copyright (C) 2005 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00016 00017 original idea: Brian Aker via playing with ab for too many years 00018 coded by: Patrick Galbraith 00019 */ 00020 00021 00022 /* 00023 MySQL Slap 00024 00025 A simple program designed to work as if multiple clients querying the database, 00026 then reporting the timing of each stage. 00027 00028 MySQL slap runs three stages: 00029 1) Create schema,table, and optionally any SP or data you want to beign 00030 the test with. (single client) 00031 2) Load test (many clients) 00032 3) Cleanup (disconnection, drop table if specified, single client) 00033 00034 Examples: 00035 00036 Supply your own create and query SQL statements, with 50 clients 00037 querying (200 selects for each): 00038 00039 mysqlslap --create="CREATE TABLE A (a int);INSERT INTO A (23)" \ 00040 --query="SELECT * FROM A" --concurrency=50 --iterations=200 00041 00042 Let the program build the query SQL statement with a table of two int 00043 columns, three varchar columns, five clients querying (20 times each), 00044 don't create the table or insert the data (using the previous test's 00045 schema and data): 00046 00047 mysqlslap --concurrency=5 --iterations=20 \ 00048 --number-int-cols=2 --number-char-cols=3 \ 00049 --auto-generate-sql 00050 00051 Tell the program to load the create, insert and query SQL statements from 00052 the specified files, where the create.sql file has multiple table creation 00053 statements delimited by ';' and multiple insert statements delimited by ';'. 00054 The --query file will have multiple queries delimited by ';', run all the 00055 load statements, and then run all the queries in the query file 00056 with five clients (five times each): 00057 00058 mysqlslap --concurrency=5 \ 00059 --iterations=5 --query=query.sql --create=create.sql \ 00060 --delimiter=";" 00061 00062 TODO: 00063 Add language for better tests 00064 String length for files and those put on the command line are not 00065 setup to handle binary data. 00066 Report results of each thread into the lock file we use. 00067 More stats 00068 Break up tests and run them on multiple hosts at once. 00069 Allow output to be fed into a database directly. 00070 00071 */ 00072 00073 #define SHOW_VERSION "0.9" 00074 00075 #define HUGE_STRING_LENGTH 8096 00076 #define RAND_STRING_SIZE 126 00077 00078 #include "client_priv.h" 00079 #ifdef HAVE_LIBPTHREAD 00080 #include <my_pthread.h> 00081 #endif 00082 #include <my_sys.h> 00083 #include <m_string.h> 00084 #include <mysql.h> 00085 #include <mysqld_error.h> 00086 #include <my_dir.h> 00087 #include <signal.h> 00088 #include <stdarg.h> 00089 #include <sslopt-vars.h> 00090 #include <sys/types.h> 00091 #ifndef __WIN__ 00092 #include <sys/wait.h> 00093 #endif 00094 #include <ctype.h> 00095 00096 #define MYSLAPLOCK "/myslaplock.lck" 00097 #define MYSLAPLOCK_DIR "/tmp" 00098 00099 #ifdef __WIN__ 00100 #define srandom srand 00101 #define random rand 00102 #define snprintf _snprintf 00103 #endif 00104 00105 #ifdef HAVE_SMEM 00106 static char *shared_memory_base_name=0; 00107 #endif 00108 00109 static char **defaults_argv; 00110 00111 static char *host= NULL, *opt_password= NULL, *user= NULL, 00112 *user_supplied_query= NULL, 00113 *default_engine= NULL, 00114 *opt_mysql_unix_port= NULL; 00115 00116 const char *delimiter= "\n"; 00117 00118 const char *create_schema_string= "mysqlslap"; 00119 00120 const char *lock_directory; 00121 char lock_file_str[FN_REFLEN]; 00122 00123 static my_bool opt_preserve; 00124 00125 static my_bool opt_only_print= FALSE; 00126 00127 static my_bool opt_slave; 00128 00129 static my_bool opt_compress= FALSE, tty_password= FALSE, 00130 opt_silent= FALSE, 00131 auto_generate_sql= FALSE; 00132 00133 static unsigned long connect_flags= CLIENT_MULTI_RESULTS; 00134 00135 static int verbose, num_int_cols, num_char_cols, delimiter_length; 00136 static int iterations; 00137 static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; 00138 static ulonglong actual_queries= 0; 00139 static ulonglong num_of_query; 00140 const char *concurrency_str= NULL; 00141 static char *create_string; 00142 uint *concurrency; 00143 00144 const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace"; 00145 const char *opt_csv_str; 00146 File csv_file; 00147 00148 static uint opt_protocol= 0; 00149 00150 static int get_options(int *argc,char ***argv); 00151 static uint opt_mysql_port= 0; 00152 static uint opt_use_threads; 00153 00154 static const char *load_default_groups[]= { "mysqlslap","client",0 }; 00155 00156 typedef struct statement statement; 00157 00158 struct statement { 00159 char *string; 00160 size_t length; 00161 statement *next; 00162 }; 00163 00164 typedef struct stats stats; 00165 00166 struct stats { 00167 long int timing; 00168 uint users; 00169 unsigned long long rows; 00170 }; 00171 00172 typedef struct thread_context thread_context; 00173 00174 struct thread_context { 00175 statement *stmt; 00176 ulonglong limit; 00177 bool thread; 00178 }; 00179 00180 typedef struct conclusions conclusions; 00181 00182 struct conclusions { 00183 char *engine; 00184 long int avg_timing; 00185 long int max_timing; 00186 long int min_timing; 00187 uint users; 00188 unsigned long long avg_rows; 00189 /* The following are not used yet */ 00190 unsigned long long max_rows; 00191 unsigned long long min_rows; 00192 }; 00193 00194 static statement *create_statements= NULL, 00195 *engine_statements= NULL, 00196 *query_statements= NULL; 00197 00198 /* Prototypes */ 00199 void print_conclusions(conclusions *con); 00200 void print_conclusions_csv(conclusions *con); 00201 void generate_stats(conclusions *con, statement *eng, stats *sptr); 00202 uint parse_comma(const char *string, uint **range); 00203 uint parse_delimiter(const char *script, statement **stmt, char delm); 00204 static int drop_schema(MYSQL *mysql, const char *db); 00205 uint get_random_string(char *buf); 00206 static statement *build_table_string(void); 00207 static statement *build_insert_string(void); 00208 static statement *build_query_string(void); 00209 static int create_schema(MYSQL *mysql, const char *db, statement *stmt, 00210 statement *engine_stmt); 00211 static int run_scheduler(stats *sptr, statement *stmts, uint concur, 00212 ulonglong limit); 00213 int run_task(thread_context *con); 00214 void statement_cleanup(statement *stmt); 00215 00216 static const char ALPHANUMERICS[]= 00217 "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; 00218 00219 #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) 00220 00221 00222 static long int timedif(struct timeval a, struct timeval b) 00223 { 00224 register int us, s; 00225 00226 us = a.tv_usec - b.tv_usec; 00227 us /= 1000; 00228 s = a.tv_sec - b.tv_sec; 00229 s *= 1000; 00230 return s + us; 00231 } 00232 00233 #ifdef __WIN__ 00234 static int gettimeofday(struct timeval *tp, void *tzp) 00235 { 00236 unsigned int ticks; 00237 ticks= GetTickCount(); 00238 tp->tv_usec= ticks*1000; 00239 tp->tv_sec= ticks/1000; 00240 00241 return 0; 00242 } 00243 #endif 00244 00245 int main(int argc, char **argv) 00246 { 00247 MYSQL mysql; 00248 int x; 00249 unsigned long long client_limit; 00250 statement *eptr; 00251 00252 #ifdef __WIN__ 00253 opt_use_threads= 1; 00254 #endif 00255 00256 MY_INIT(argv[0]); 00257 00258 load_defaults("my",load_default_groups,&argc,&argv); 00259 defaults_argv=argv; 00260 if (get_options(&argc,&argv)) 00261 { 00262 free_defaults(defaults_argv); 00263 my_end(0); 00264 exit(1); 00265 } 00266 00267 /* Seed the random number generator if we will be using it. */ 00268 if (auto_generate_sql) 00269 srandom((uint)time(NULL)); 00270 00271 /* globals? Yes, so we only have to run strlen once */ 00272 delimiter_length= strlen(delimiter); 00273 00274 if (argc > 2) 00275 { 00276 fprintf(stderr,"%s: Too many arguments\n",my_progname); 00277 free_defaults(defaults_argv); 00278 my_end(0); 00279 exit(1); 00280 } 00281 mysql_init(&mysql); 00282 if (opt_compress) 00283 mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); 00284 #ifdef HAVE_OPENSSL 00285 if (opt_use_ssl) 00286 mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, 00287 opt_ssl_capath, opt_ssl_cipher); 00288 #endif 00289 if (opt_protocol) 00290 mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); 00291 #ifdef HAVE_SMEM 00292 if (shared_memory_base_name) 00293 mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); 00294 #endif 00295 mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); 00296 00297 if (!opt_only_print) 00298 { 00299 if (!(mysql_real_connect(&mysql, host, user, opt_password, 00300 NULL, opt_mysql_port, 00301 opt_mysql_unix_port, connect_flags))) 00302 { 00303 fprintf(stderr,"%s: Error when connecting to server: %s\n", 00304 my_progname,mysql_error(&mysql)); 00305 free_defaults(defaults_argv); 00306 my_end(0); 00307 exit(1); 00308 } 00309 } 00310 00311 /* Main iterations loop */ 00312 eptr= engine_statements; 00313 do 00314 { 00315 /* For the final stage we run whatever queries we were asked to run */ 00316 uint *current; 00317 conclusions conclusion; 00318 00319 for (current= concurrency; current && *current; current++) 00320 { 00321 stats *head_sptr; 00322 stats *sptr; 00323 00324 head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, MYF(MY_ZEROFILL)); 00325 00326 bzero(&conclusion, sizeof(conclusions)); 00327 00328 if (num_of_query) 00329 client_limit= num_of_query / *current; 00330 else 00331 client_limit= actual_queries; 00332 00333 for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++) 00334 { 00335 /* 00336 We might not want to load any data, such as when we are calling 00337 a stored_procedure that doesn't use data, or we know we already have 00338 data in the table. 00339 */ 00340 if (!opt_preserve) 00341 drop_schema(&mysql, create_schema_string); 00342 /* First we create */ 00343 if (create_statements) 00344 create_schema(&mysql, create_schema_string, create_statements, eptr); 00345 00346 run_scheduler(sptr, query_statements, *current, client_limit); 00347 } 00348 00349 generate_stats(&conclusion, eptr, head_sptr); 00350 00351 if (!opt_silent) 00352 print_conclusions(&conclusion); 00353 if (opt_csv_str) 00354 print_conclusions_csv(&conclusion); 00355 00356 my_free((byte *)head_sptr, MYF(0)); 00357 } 00358 00359 if (!opt_preserve) 00360 drop_schema(&mysql, create_schema_string); 00361 } while (eptr ? (eptr= eptr->next) : 0); 00362 00363 if (!opt_only_print) 00364 mysql_close(&mysql); /* Close & free connection */ 00365 00366 00367 /* Remove lock file */ 00368 my_delete(lock_file_str, MYF(0)); 00369 00370 /* now free all the strings we created */ 00371 if (opt_password) 00372 my_free(opt_password, MYF(0)); 00373 00374 my_free((byte *)concurrency, MYF(0)); 00375 00376 statement_cleanup(create_statements); 00377 statement_cleanup(engine_statements); 00378 statement_cleanup(query_statements); 00379 00380 #ifdef HAVE_SMEM 00381 if (shared_memory_base_name) 00382 my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); 00383 #endif 00384 free_defaults(defaults_argv); 00385 my_end(0); 00386 00387 return 0; 00388 } 00389 00390 00391 static struct my_option my_long_options[] = 00392 { 00393 {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 00394 0, 0, 0, 0, 0, 0}, 00395 {"auto-generate-sql", 'a', 00396 "Generate SQL where not supplied by file or command line.", 00397 (gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql, 00398 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00399 {"compress", 'C', "Use compression in server/client protocol.", 00400 (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 00401 0, 0, 0}, 00402 {"concurrency", 'c', "Number of clients to simulate for query to run.", 00403 (gptr*) &concurrency_str, (gptr*) &concurrency_str, 0, GET_STR, 00404 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00405 {"create", OPT_CREATE_SLAP_SCHEMA, "File or string to use create tables.", 00406 (gptr*) &create_string, (gptr*) &create_string, 0, GET_STR, REQUIRED_ARG, 00407 0, 0, 0, 0, 0, 0}, 00408 {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.", 00409 (gptr*) &create_schema_string, (gptr*) &create_schema_string, 0, GET_STR, 00410 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00411 {"csv", OPT_CREATE_SLAP_SCHEMA, 00412 "Generate CSV output to named file or to stdout if no file is named.", 00413 (gptr*) &opt_csv_str, (gptr*) &opt_csv_str, 0, GET_STR, 00414 OPT_ARG, 0, 0, 0, 0, 0, 0}, 00415 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 00416 (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, 00417 OPT_ARG, 0, 0, 0, 0, 0, 0}, 00418 {"delimiter", 'F', 00419 "Delimiter to use in SQL statements supplied in file or command line.", 00420 (gptr*) &delimiter, (gptr*) &delimiter, 0, GET_STR, REQUIRED_ARG, 00421 0, 0, 0, 0, 0, 0}, 00422 {"engine", 'e', "Storage engine to use for creating the table.", 00423 (gptr*) &default_engine, (gptr*) &default_engine, 0, 00424 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00425 {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, 00426 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00427 {"iterations", 'i', "Number of times too run the tests.", (gptr*) &iterations, 00428 (gptr*) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, 00429 {"lock-directory", OPT_MYSQL_LOCK_DIRECTORY, "Directory to use to keep locks.", 00430 (gptr*) &lock_directory, (gptr*) &lock_directory, 0, GET_STR, 00431 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00432 {"number-char-cols", 'x', 00433 "Number of INT columns to create table with if specifying --auto-generate-sql.", 00434 (gptr*) &num_char_cols, (gptr*) &num_char_cols, 0, GET_UINT, REQUIRED_ARG, 00435 1, 0, 0, 0, 0, 0}, 00436 {"number-int-cols", 'y', 00437 "Number of VARCHAR columns to create table with if specifying " 00438 "--auto-generate-sql.", (gptr*) &num_int_cols, (gptr*) &num_int_cols, 0, 00439 GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, 00440 {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY, 00441 "Limit each client to this number of queries (this is not exact).", 00442 (gptr*) &num_of_query, (gptr*) &num_of_query, 0, 00443 GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00444 {"only-print", OPT_MYSQL_ONLY_PRINT, 00445 "This causes mysqlslap to not connect to the databases, but instead print " 00446 "out what it would have done instead.", 00447 (gptr*) &opt_only_print, (gptr*) &opt_only_print, 0, GET_BOOL, NO_ARG, 00448 0, 0, 0, 0, 0, 0}, 00449 {"password", 'p', 00450 "Password to use when connecting to server. If password is not given it's " 00451 "asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00452 #ifdef __WIN__ 00453 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, 00454 NO_ARG, 0, 0, 0, 0, 0, 0}, 00455 #endif 00456 {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, 00457 (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 00458 0}, 00459 {"preserve-schema", OPT_MYSQL_PRESERVE_SCHEMA, 00460 "Preserve the schema from the mysqlslap run, this happens unless " 00461 "--auto-generate-sql or --create are used.", 00462 (gptr*) &opt_preserve, (gptr*) &opt_preserve, 0, GET_BOOL, 00463 NO_ARG, TRUE, 0, 0, 0, 0, 0}, 00464 {"protocol", OPT_MYSQL_PROTOCOL, 00465 "The protocol of connection (tcp,socket,pipe,memory).", 00466 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00467 {"query", 'q', "Query to run or file containing query to run.", 00468 (gptr*) &user_supplied_query, (gptr*) &user_supplied_query, 00469 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00470 #ifdef HAVE_SMEM 00471 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, 00472 "Base name of shared memory.", (gptr*) &shared_memory_base_name, 00473 (gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 00474 0, 0, 0, 0, 0, 0}, 00475 #endif 00476 {"silent", 's', "Run program in silent mode - no output.", 00477 (gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 00478 0, 0, 0, 0, 0, 0}, 00479 {"slave", OPT_MYSQL_SLAP_SLAVE, "Follow master locks for other slap clients", 00480 (gptr*) &opt_slave, (gptr*) &opt_slave, 0, GET_BOOL, NO_ARG, 00481 0, 0, 0, 0, 0, 0}, 00482 {"socket", 'S', "Socket file to use for connection.", 00483 (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, 00484 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00485 #include <sslopt-longopts.h> 00486 {"use-threads", OPT_USE_THREADS, 00487 "Use pthread calls instead of fork() calls (default on Windows)", 00488 (gptr*) &opt_use_threads, (gptr*) &opt_use_threads, 0, 00489 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00490 #ifndef DONT_ALLOW_USER_CHANGE 00491 {"user", 'u', "User for login if not current user.", (gptr*) &user, 00492 (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00493 #endif 00494 {"verbose", 'v', 00495 "More verbose output; You can use this multiple times to get even more " 00496 "verbose output.", (gptr*) &verbose, (gptr*) &verbose, 0, 00497 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00498 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, 00499 NO_ARG, 0, 0, 0, 0, 0, 0}, 00500 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} 00501 }; 00502 00503 00504 #include <help_start.h> 00505 00506 static void print_version(void) 00507 { 00508 printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, 00509 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); 00510 } 00511 00512 00513 static void usage(void) 00514 { 00515 print_version(); 00516 puts("Copyright (C) 2005 MySQL AB"); 00517 puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\ 00518 \nand you are welcome to modify and redistribute it under the GPL \ 00519 license\n"); 00520 puts("Run a query multiple times against the server\n"); 00521 printf("Usage: %s [OPTIONS]\n",my_progname); 00522 print_defaults("my",load_default_groups); 00523 my_print_help(my_long_options); 00524 } 00525 00526 #include <help_end.h> 00527 00528 static my_bool 00529 get_one_option(int optid, const struct my_option *opt __attribute__((unused)), 00530 char *argument) 00531 { 00532 DBUG_ENTER("get_one_option"); 00533 switch(optid) { 00534 #ifdef __NETWARE__ 00535 case OPT_AUTO_CLOSE: 00536 setscreenmode(SCR_AUTOCLOSE_ON_EXIT); 00537 break; 00538 #endif 00539 case 'v': 00540 verbose++; 00541 break; 00542 case 'p': 00543 if (argument) 00544 { 00545 char *start= argument; 00546 my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); 00547 opt_password= my_strdup(argument,MYF(MY_FAE)); 00548 while (*argument) *argument++= 'x'; /* Destroy argument */ 00549 if (*start) 00550 start[1]= 0; /* Cut length of argument */ 00551 tty_password= 0; 00552 } 00553 else 00554 tty_password= 1; 00555 break; 00556 case 'W': 00557 #ifdef __WIN__ 00558 opt_protocol= MYSQL_PROTOCOL_PIPE; 00559 #endif 00560 break; 00561 case OPT_MYSQL_PROTOCOL: 00562 { 00563 if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) 00564 { 00565 fprintf(stderr, "Unknown option to protocol: %s\n", argument); 00566 exit(1); 00567 } 00568 break; 00569 } 00570 case '#': 00571 DBUG_PUSH(argument ? argument : default_dbug_option); 00572 break; 00573 #include <sslopt-case.h> 00574 case 'V': 00575 print_version(); 00576 exit(0); 00577 break; 00578 case '?': 00579 case 'I': /* Info */ 00580 usage(); 00581 exit(0); 00582 } 00583 DBUG_RETURN(0); 00584 } 00585 00586 00587 uint 00588 get_random_string(char *buf) 00589 { 00590 char *buf_ptr= buf; 00591 int x; 00592 DBUG_ENTER("get_random_string"); 00593 for (x= RAND_STRING_SIZE; x > 0; x--) 00594 *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; 00595 DBUG_PRINT("info", ("random string: '%*s'", buf_ptr - buf, buf)); 00596 DBUG_RETURN(buf_ptr - buf); 00597 } 00598 00599 00600 /* 00601 build_table_string 00602 00603 This function builds a create table query if the user opts to not supply 00604 a file or string containing a create table statement 00605 */ 00606 static statement * 00607 build_table_string(void) 00608 { 00609 char buf[512]; 00610 int col_count; 00611 statement *ptr; 00612 DYNAMIC_STRING table_string; 00613 DBUG_ENTER("build_table_string"); 00614 00615 DBUG_PRINT("info", ("num int cols %d num char cols %d", 00616 num_int_cols, num_char_cols)); 00617 00618 init_dynamic_string(&table_string, "", 1024, 1024); 00619 00620 dynstr_append(&table_string, "CREATE TABLE `t1` ("); 00621 for (col_count= 1; col_count <= num_int_cols; col_count++) 00622 { 00623 sprintf(buf, "intcol%d INT(32)", col_count); 00624 dynstr_append(&table_string, buf); 00625 00626 if (col_count < num_int_cols || num_char_cols > 0) 00627 dynstr_append(&table_string, ","); 00628 } 00629 for (col_count= 1; col_count <= num_char_cols; col_count++) 00630 { 00631 sprintf(buf, "charcol%d VARCHAR(128)", col_count); 00632 dynstr_append(&table_string, buf); 00633 00634 if (col_count < num_char_cols) 00635 dynstr_append(&table_string, ","); 00636 } 00637 dynstr_append(&table_string, ")"); 00638 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00639 ptr->string = (char *)my_malloc(table_string.length+1, MYF(MY_WME)); 00640 ptr->length= table_string.length+1; 00641 strmov(ptr->string, table_string.str); 00642 DBUG_PRINT("info", ("create_string %s", ptr->string)); 00643 dynstr_free(&table_string); 00644 DBUG_RETURN(ptr); 00645 } 00646 00647 00648 /* 00649 build_insert_string() 00650 00651 This function builds insert statements when the user opts to not supply 00652 an insert file or string containing insert data 00653 */ 00654 static statement * 00655 build_insert_string(void) 00656 { 00657 char buf[RAND_STRING_SIZE]; 00658 int col_count; 00659 statement *ptr; 00660 DYNAMIC_STRING insert_string; 00661 DBUG_ENTER("build_insert_string"); 00662 00663 init_dynamic_string(&insert_string, "", 1024, 1024); 00664 00665 dynstr_append_mem(&insert_string, "INSERT INTO t1 VALUES (", 23); 00666 for (col_count= 1; col_count <= num_int_cols; col_count++) 00667 { 00668 sprintf(buf, "%ld", random()); 00669 dynstr_append(&insert_string, buf); 00670 00671 if (col_count < num_int_cols || num_char_cols > 0) 00672 dynstr_append_mem(&insert_string, ",", 1); 00673 } 00674 for (col_count= 1; col_count <= num_char_cols; col_count++) 00675 { 00676 int buf_len= get_random_string(buf); 00677 dynstr_append_mem(&insert_string, "'", 1); 00678 dynstr_append_mem(&insert_string, buf, buf_len); 00679 dynstr_append_mem(&insert_string, "'", 1); 00680 00681 if (col_count < num_char_cols) 00682 dynstr_append_mem(&insert_string, ",", 1); 00683 } 00684 dynstr_append_mem(&insert_string, ")", 1); 00685 00686 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00687 ptr->string= (char *)my_malloc(insert_string.length+1, MYF(MY_WME)); 00688 ptr->length= insert_string.length+1; 00689 strmov(ptr->string, insert_string.str); 00690 DBUG_PRINT("info", ("generated_insert_data %s", ptr->string)); 00691 dynstr_free(&insert_string); 00692 DBUG_RETURN(ptr); 00693 } 00694 00695 00696 /* 00697 build_query_string() 00698 00699 This function builds a query if the user opts to not supply a query 00700 statement or file containing a query statement 00701 */ 00702 static statement * 00703 build_query_string(void) 00704 { 00705 char buf[512]; 00706 int col_count; 00707 statement *ptr; 00708 static DYNAMIC_STRING query_string; 00709 DBUG_ENTER("build_query_string"); 00710 00711 init_dynamic_string(&query_string, "", 1024, 1024); 00712 00713 dynstr_append_mem(&query_string, "SELECT ", 7); 00714 for (col_count= 1; col_count <= num_int_cols; col_count++) 00715 { 00716 sprintf(buf, "intcol%d", col_count); 00717 dynstr_append(&query_string, buf); 00718 00719 if (col_count < num_int_cols || num_char_cols > 0) 00720 dynstr_append_mem(&query_string, ",", 1); 00721 00722 } 00723 for (col_count= 1; col_count <= num_char_cols; col_count++) 00724 { 00725 sprintf(buf, "charcol%d", col_count); 00726 dynstr_append(&query_string, buf); 00727 00728 if (col_count < num_char_cols) 00729 dynstr_append_mem(&query_string, ",", 1); 00730 00731 } 00732 dynstr_append_mem(&query_string, " FROM t1", 8); 00733 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00734 ptr->string= (char *)my_malloc(query_string.length+1, MYF(MY_WME)); 00735 ptr->length= query_string.length+1; 00736 strmov(ptr->string, query_string.str); 00737 DBUG_PRINT("info", ("user_supplied_query %s", ptr->string)); 00738 dynstr_free(&query_string); 00739 DBUG_RETURN(ptr); 00740 } 00741 00742 static int 00743 get_options(int *argc,char ***argv) 00744 { 00745 int ho_error; 00746 char *tmp_string; 00747 MY_STAT sbuf; /* Stat information for the data file */ 00748 00749 DBUG_ENTER("get_options"); 00750 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) 00751 exit(ho_error); 00752 00753 if (!user) 00754 user= (char *)"root"; 00755 00756 if (create_string || auto_generate_sql) 00757 { 00758 if (verbose >= 1) 00759 fprintf(stderr, "Turning off preserve-schema!\n"); 00760 opt_preserve= FALSE; 00761 } 00762 00763 if (auto_generate_sql && (create_string || user_supplied_query)) 00764 { 00765 fprintf(stderr, 00766 "%s: Can't use --auto-generate-sql when create and query strings are specified!\n", 00767 my_progname); 00768 exit(1); 00769 } 00770 00771 parse_comma(concurrency_str ? concurrency_str : "1", &concurrency); 00772 00773 if (lock_directory) 00774 snprintf(lock_file_str, FN_REFLEN, "%s/%s", lock_directory, MYSLAPLOCK); 00775 else 00776 snprintf(lock_file_str, FN_REFLEN, "%s/%s", MYSLAPLOCK_DIR, MYSLAPLOCK); 00777 00778 if (opt_csv_str) 00779 { 00780 opt_silent=

