~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2005 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15
16
   original idea: Brian Aker via playing with ab for too many years
17
   coded by: Patrick Galbraith
18
*/
19
20
21
/*
22
  MySQL Slap
23
24
  A simple program designed to work as if multiple clients querying the database,
25
  then reporting the timing of each stage.
26
27
  MySQL slap runs three stages:
28
  1) Create schema,table, and optionally any SP or data you want to beign
29
     the test with. (single client)
30
  2) Load test (many clients)
31
  3) Cleanup (disconnection, drop table if specified, single client)
32
33
  Examples:
34
35
  Supply your own create and query SQL statements, with 50 clients 
36
  querying (200 selects for each):
37
38
    mysqlslap --delimiter=";" \
39
              --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
40
              --query="SELECT * FROM A" --concurrency=50 --iterations=200
41
42
  Let the program build the query SQL statement with a table of two int
43
  columns, three varchar columns, five clients querying (20 times each),
44
  don't create the table or insert the data (using the previous test's
45
  schema and data):
46
47
    mysqlslap --concurrency=5 --iterations=20 \
48
              --number-int-cols=2 --number-char-cols=3 \
49
              --auto-generate-sql
50
51
  Tell the program to load the create, insert and query SQL statements from
52
  the specified files, where the create.sql file has multiple table creation
53
  statements delimited by ';' and multiple insert statements delimited by ';'.
54
  The --query file will have multiple queries delimited by ';', run all the 
55
  load statements, and then run all the queries in the query file
56
  with five clients (five times each):
57
58
    mysqlslap --concurrency=5 \
59
              --iterations=5 --query=query.sql --create=create.sql \
60
              --delimiter=";"
61
62
TODO:
63
  Add language for better tests
64
  String length for files and those put on the command line are not
65
    setup to handle binary data.
66
  More stats
67
  Break up tests and run them on multiple hosts at once.
68
  Allow output to be fed into a database directly.
69
70
*/
71
72
#define SLAP_VERSION "1.5"
73
74
#define HUGE_STRING_LENGTH 8196
75
#define RAND_STRING_SIZE 126
76
#define DEFAULT_BLOB_SIZE 1024
77
78
#include "client_priv.h"
79
#include <mysqld_error.h>
80
#include <my_dir.h>
81
#include <signal.h>
82
#include <stdarg.h>
83
#include <sys/types.h>
84
#include <sys/wait.h>
85
#include <ctype.h>
86
87
#ifdef HAVE_SMEM 
88
static char *shared_memory_base_name=0;
89
#endif
90
91
/* Global Thread counter */
92
uint thread_counter;
93
pthread_mutex_t counter_mutex;
94
pthread_cond_t count_threshhold;
95
uint master_wakeup;
96
pthread_mutex_t sleeper_mutex;
97
pthread_cond_t sleep_threshhold;
98
99
/* Global Thread timer */
163 by Brian Aker
Merge Monty's code.
100
static bool timer_alarm= false;
1 by brian
clean slate
101
pthread_mutex_t timer_alarm_mutex;
102
pthread_cond_t timer_alarm_threshold;
103
104
static char **defaults_argv;
105
106
char **primary_keys;
107
unsigned long long primary_keys_number_of;
108
109
static char *host= NULL, *opt_password= NULL, *user= NULL,
110
            *user_supplied_query= NULL,
111
            *user_supplied_pre_statements= NULL,
112
            *user_supplied_post_statements= NULL,
113
            *default_engine= NULL,
114
            *pre_system= NULL,
115
            *post_system= NULL,
116
            *opt_mysql_unix_port= NULL;
117
118
const char *delimiter= "\n";
119
120
const char *create_schema_string= "mysqlslap";
121
163 by Brian Aker
Merge Monty's code.
122
static bool opt_preserve= true;
143 by Brian Aker
Bool cleanup.
123
static bool debug_info_flag= 0, debug_check_flag= 0;
163 by Brian Aker
Merge Monty's code.
124
static bool opt_only_print= false;
125
static bool opt_burnin= false;
126
static bool opt_ignore_sql_errors= false;
127
static bool opt_compress= false, tty_password= false,
128
               opt_silent= false,
129
               auto_generate_sql_autoincrement= false,
130
               auto_generate_sql_guid_primary= false,
131
               auto_generate_sql= false;
1 by brian
clean slate
132
const char *opt_auto_generate_sql_type= "mixed";
133
134
static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
135
                                    CLIENT_MULTI_STATEMENTS;
136
137
static int verbose, delimiter_length;
138
static uint commit_rate;
139
static uint detach_rate;
140
static uint opt_timer_length;
141
static uint opt_delayed_start;
142
const char *num_int_cols_opt;
143
const char *num_char_cols_opt;
144
const char *num_blob_cols_opt;
145
const char *opt_label;
146
static unsigned int opt_set_random_seed;
147
148
const char *auto_generate_selected_columns_opt;
149
150
/* Yes, we do set defaults here */
151
static unsigned int num_int_cols= 1;
152
static unsigned int num_char_cols= 1;
153
static unsigned int num_blob_cols= 0;
154
static unsigned int num_blob_cols_size;
155
static unsigned int num_blob_cols_size_min;
156
static unsigned int num_int_cols_index= 0; 
157
static unsigned int num_char_cols_index= 0;
158
static unsigned int iterations;
159
static uint my_end_arg= 0;
160
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
151 by Brian Aker
Ulonglong to uint64_t
161
static uint64_t actual_queries= 0;
162
static uint64_t auto_actual_queries;
163
static uint64_t auto_generate_sql_unique_write_number;
164
static uint64_t auto_generate_sql_unique_query_number;
1 by brian
clean slate
165
static unsigned int auto_generate_sql_secondary_indexes;
151 by Brian Aker
Ulonglong to uint64_t
166
static uint64_t num_of_query;
167
static uint64_t auto_generate_sql_number;
1 by brian
clean slate
168
const char *concurrency_str= NULL;
169
static char *create_string;
170
uint *concurrency;
171
172
const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
173
const char *opt_csv_str;
174
File csv_file;
175
176
static uint opt_protocol= MYSQL_PROTOCOL_TCP;
177
178
static int get_options(int *argc,char ***argv);
179
static uint opt_mysql_port= 0;
180
181
static const char *load_default_groups[]= { "mysqlslap","client",0 };
182
183
/* Types */
184
typedef enum {
185
  SELECT_TYPE= 0,
186
  UPDATE_TYPE= 1,
187
  INSERT_TYPE= 2,
188
  UPDATE_TYPE_REQUIRES_PREFIX= 3,
189
  CREATE_TABLE_TYPE= 4,
190
  SELECT_TYPE_REQUIRES_PREFIX= 5,
191
  DELETE_TYPE_REQUIRES_PREFIX= 6
192
} slap_query_type;
193
194
typedef struct statement statement;
195
196
struct statement {
197
  char *string;
198
  size_t length;
199
  slap_query_type type;
200
  char *option;
201
  size_t option_length;
202
  statement *next;
203
};
204
205
typedef struct option_string option_string;
206
207
struct option_string {
208
  char *string;
209
  size_t length;
210
  char *option;
211
  size_t option_length;
212
  option_string *next;
213
};
214
215
typedef struct stats stats;
216
217
struct stats {
218
  long int timing;
219
  uint users;
220
  uint real_users;
221
  unsigned long long rows;
222
  long int create_timing;
223
  unsigned long long create_count;
224
};
225
226
typedef struct thread_context thread_context;
227
228
struct thread_context {
229
  statement *stmt;
151 by Brian Aker
Ulonglong to uint64_t
230
  uint64_t limit;
1 by brian
clean slate
231
};
232
233
typedef struct conclusions conclusions;
234
235
struct conclusions {
236
  char *engine;
237
  long int avg_timing;
238
  long int max_timing;
239
  long int min_timing;
240
  uint users;
241
  uint real_users;
242
  unsigned long long avg_rows;
243
  long int sum_of_time;
244
  long int std_dev;
245
  /* These are just for create time stats */
246
  long int create_avg_timing;
247
  long int create_max_timing;
248
  long int create_min_timing;
249
  unsigned long long create_count;
250
  /* The following are not used yet */
251
  unsigned long long max_rows;
252
  unsigned long long min_rows;
253
};
254
255
static option_string *engine_options= NULL;
256
static option_string *query_options= NULL; 
257
static statement *pre_statements= NULL; 
258
static statement *post_statements= NULL; 
259
static statement *create_statements= NULL;
260
261
static statement **query_statements= NULL;
262
static unsigned int query_statements_count;
263
264
265
/* Prototypes */
266
void print_conclusions(conclusions *con);
267
void print_conclusions_csv(conclusions *con);
268
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
269
uint parse_comma(const char *string, uint **range);
270
uint parse_delimiter(const char *script, statement **stmt, char delm);
271
uint parse_option(const char *origin, option_string **stmt, char delm);
272
static int drop_schema(MYSQL *mysql, const char *db);
273
uint get_random_string(char *buf, size_t size);
274
static statement *build_table_string(void);
275
static statement *build_insert_string(void);
276
static statement *build_update_string(void);
143 by Brian Aker
Bool cleanup.
277
static statement * build_select_string(bool key);
1 by brian
clean slate
278
static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt);
279
static int drop_primary_key_list(void);
280
static int create_schema(MYSQL *mysql, const char *db, statement *stmt, 
281
                         option_string *engine_stmt, stats *sptr);
282
static int run_scheduler(stats *sptr, statement **stmts, uint concur, 
151 by Brian Aker
Ulonglong to uint64_t
283
                         uint64_t limit);
1 by brian
clean slate
284
pthread_handler_t run_task(void *p);
285
pthread_handler_t timer_thread(void *p);
286
void statement_cleanup(statement *stmt);
287
void option_cleanup(option_string *stmt);
288
void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr);
289
static int run_statements(MYSQL *mysql, statement *stmt);
143 by Brian Aker
Bool cleanup.
290
void slap_connect(MYSQL *mysql, bool connect_to_schema);
1 by brian
clean slate
291
void slap_close(MYSQL *mysql);
292
static int run_query(MYSQL *mysql, const char *query, int len);
293
void standard_deviation (conclusions *con, stats *sptr);
294
295
static const char ALPHANUMERICS[]=
296
  "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
297
298
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
299
300
301
static long int timedif(struct timeval a, struct timeval b)
302
{
303
    register int us, s;
304
 
305
    us = a.tv_usec - b.tv_usec;
306
    us /= 1000;
307
    s = a.tv_sec - b.tv_sec;
308
    s *= 1000;
309
    return s + us;
310
}
311
312
int main(int argc, char **argv)
313
{
314
  MYSQL mysql;
315
  option_string *eptr;
316
  unsigned int x;
317
318
  my_init();
319
320
  MY_INIT(argv[0]);
321
322
  if (!(mysql_thread_safe()))
323
      fprintf(stderr, "This application was compiled incorrectly. Please recompile with thread support.\n");
324
325
  load_defaults("my",load_default_groups,&argc,&argv);
326
  defaults_argv=argv;
327
  if (get_options(&argc,&argv))
328
  {
329
    free_defaults(defaults_argv);
330
    my_end(0);
331
    exit(1);
332
  }
333
334
  /* Seed the random number generator if we will be using it. */
335
  if (auto_generate_sql)
336
  {
337
    if (opt_set_random_seed == 0)
338
      opt_set_random_seed= (unsigned int)time(NULL);
339
    srandom(opt_set_random_seed);
340
  }
341
342
  /* globals? Yes, so we only have to run strlen once */
343
  delimiter_length= strlen(delimiter);
344
345
  if (argc > 2)
346
  {
347
    fprintf(stderr,"%s: Too many arguments\n",my_progname);
348
    free_defaults(defaults_argv);
349
    my_end(0);
350
    exit(1);
351
  }
352
163 by Brian Aker
Merge Monty's code.
353
  slap_connect(&mysql, false);
1 by brian
clean slate
354
355
  VOID(pthread_mutex_init(&counter_mutex, NULL));
356
  VOID(pthread_cond_init(&count_threshhold, NULL));
357
  VOID(pthread_mutex_init(&sleeper_mutex, NULL));
358
  VOID(pthread_cond_init(&sleep_threshhold, NULL));
359
  VOID(pthread_mutex_init(&timer_alarm_mutex, NULL));
360
  VOID(pthread_cond_init(&timer_alarm_threshold, NULL));
361
362
363
  /* Main iterations loop */
364
burnin:
365
  eptr= engine_options;
366
  do
367
  {
368
    /* For the final stage we run whatever queries we were asked to run */
369
    uint *current;
370
371
    if (verbose >= 2)
372
      printf("Starting Concurrency Test\n");
373
374
    if (*concurrency)
375
    {
376
      for (current= concurrency; current && *current; current++)
377
        concurrency_loop(&mysql, *current, eptr);
378
    }
379
    else
380
    {
381
      uint infinite= 1;
382
      do {
383
        concurrency_loop(&mysql, infinite, eptr);
384
      }
385
      while (infinite++);
386
    }
387
388
    if (!opt_preserve)
389
      drop_schema(&mysql, create_schema_string);
390
391
  } while (eptr ? (eptr= eptr->next) : 0);
392
  
393
  if (opt_burnin)
394
    goto burnin;
395
396
  VOID(pthread_mutex_destroy(&counter_mutex));
397
  VOID(pthread_cond_destroy(&count_threshhold));
398
  VOID(pthread_mutex_destroy(&sleeper_mutex));
399
  VOID(pthread_cond_destroy(&sleep_threshhold));
400
  VOID(pthread_mutex_destroy(&timer_alarm_mutex));
401
  VOID(pthread_cond_destroy(&timer_alarm_threshold));
402
403
  slap_close(&mysql);
404
405
  /* now free all the strings we created */
406
  if (opt_password)
407
    my_free(opt_password, MYF(0));
408
409
  my_free(concurrency, MYF(0));
410
411
  statement_cleanup(create_statements);
412
  for (x= 0; x < query_statements_count; x++)
413
    statement_cleanup(query_statements[x]);
414
  my_free(query_statements, MYF(0));
415
  statement_cleanup(pre_statements);
416
  statement_cleanup(post_statements);
417
  option_cleanup(engine_options);
418
  option_cleanup(query_options);
419
420
#ifdef HAVE_SMEM
421
  if (shared_memory_base_name)
422
    my_free(shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR));
423
#endif
424
  free_defaults(defaults_argv);
425
  my_end(my_end_arg);
426
427
  return 0;
428
}
429
430
void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
431
{
432
  unsigned int x;
433
  stats *head_sptr;
434
  stats *sptr;
435
  conclusions conclusion;
436
  unsigned long long client_limit;
437
438
  head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, 
439
                                MYF(MY_ZEROFILL|MY_FAE|MY_WME));
440
441
  bzero(&conclusion, sizeof(conclusions));
442
443
  if (auto_actual_queries)
444
    client_limit= auto_actual_queries;
445
  else if (num_of_query)
446
    client_limit=  num_of_query / current;
447
  else
448
    client_limit= actual_queries;
449
450
  for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
451
  {
452
    /*
453
      We might not want to load any data, such as when we are calling
454
      a stored_procedure that doesn't use data, or we know we already have
455
      data in the table.
456
    */
163 by Brian Aker
Merge Monty's code.
457
    if (opt_preserve == false)
1 by brian
clean slate
458
      drop_schema(mysql, create_schema_string);
459
460
    /* First we create */
461
    if (create_statements)
462
      create_schema(mysql, create_schema_string, create_statements, eptr, sptr);
463
464
    /*
465
      If we generated GUID we need to build a list of them from creation that
466
      we can later use.
467
    */
468
    if (verbose >= 2)
469
      printf("Generating primary key list\n");
470
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
471
      generate_primary_key_list(mysql, eptr);
472
473
    if (commit_rate)
474
      run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
475
476
    if (pre_system)
477
      system(pre_system);
478
479
    /* 
480
      Pre statements are always run after all other logic so they can 
481
      correct/adjust any item that they want. 
482
    */
483
    if (pre_statements)
484
      run_statements(mysql, pre_statements);
485
486
    run_scheduler(sptr, query_statements, current, client_limit); 
487
    
488
    if (post_statements)
489
      run_statements(mysql, post_statements);
490
491
    if (post_system)
492
      system(post_system);
493
494
    /* We are finished with this run */
495
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
496
      drop_primary_key_list();
497
  }
498
499
  if (verbose >= 2)
500
    printf("Generating stats\n");
501
502
  generate_stats(&conclusion, eptr, head_sptr);
503
504
  if (!opt_silent)
505
    print_conclusions(&conclusion);
506
  if (opt_csv_str)
507
    print_conclusions_csv(&conclusion);
508
509
  my_free(head_sptr, MYF(0));
510
511
}
512
513
514
static struct my_option my_long_options[] =
515
{
516
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
517
    0, 0, 0, 0, 0, 0},
518
  {"auto-generate-sql-select-columns", OPT_SLAP_AUTO_GENERATE_SELECT_COLUMNS,
519
    "Provide a string to use for the select fields used in auto tests.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
520
    (char**) &auto_generate_selected_columns_opt, 
521
    (char**) &auto_generate_selected_columns_opt,
1 by brian
clean slate
522
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
523
  {"auto-generate-sql", 'a',
524
    "Generate SQL where not supplied by file or command line.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
525
    (char**) &auto_generate_sql, (char**) &auto_generate_sql,
1 by brian
clean slate
526
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
527
  {"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
528
    "Add an AUTO_INCREMENT column to auto-generated tables.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
529
    (char**) &auto_generate_sql_autoincrement, 
530
    (char**) &auto_generate_sql_autoincrement,
1 by brian
clean slate
531
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
532
  {"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
533
    "Set this number to generate a set number of queries to run.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
534
    (char**) &auto_actual_queries, (char**) &auto_actual_queries,
1 by brian
clean slate
535
    0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
536
  {"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
537
    "Add GUID based primary keys to auto-generated tables.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
538
    (char**) &auto_generate_sql_guid_primary, 
539
    (char**) &auto_generate_sql_guid_primary,
1 by brian
clean slate
540
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
541
  {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
542
    "Specify test load type: mixed, update, write, key, or read; default is mixed.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
543
    (char**) &opt_auto_generate_sql_type, (char**) &opt_auto_generate_sql_type,
1 by brian
clean slate
544
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
545
  {"auto-generate-sql-secondary-indexes", 
546
    OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES, 
547
    "Number of secondary indexes to add to auto-generated tables.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
548
    (char**) &auto_generate_sql_secondary_indexes, 
549
    (char**) &auto_generate_sql_secondary_indexes, 0,
1 by brian
clean slate
550
    GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
551
  {"auto-generate-sql-unique-query-number", 
552
    OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
553
    "Number of unique queries to generate for automatic tests.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
554
    (char**) &auto_generate_sql_unique_query_number, 
555
    (char**) &auto_generate_sql_unique_query_number,
1 by brian
clean slate
556
    0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
557
  {"auto-generate-sql-unique-write-number", 
558
    OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
559
    "Number of unique queries to generate for auto-generate-sql-write-number.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
560
    (char**) &auto_generate_sql_unique_write_number, 
561
    (char**) &auto_generate_sql_unique_write_number,
1 by brian
clean slate
562
    0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
563
  {"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
564
    "Number of row inserts to perform for each thread (default is 100).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
565
    (char**) &auto_generate_sql_number, (char**) &auto_generate_sql_number,
1 by brian
clean slate
566
    0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
567
  {"burnin", OPT_SLAP_BURNIN, "Run full test case in infinite loop.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
568
    (char**) &opt_burnin, (char**) &opt_burnin, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1 by brian
clean slate
569
    0, 0, 0},
570
  {"ignore-sql-errors", OPT_SLAP_IGNORE_SQL_ERRORS, 
571
    "Ignore SQL erros in query run.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
572
    (char**) &opt_ignore_sql_errors, 
573
    (char**) &opt_ignore_sql_errors, 
1 by brian
clean slate
574
    0, GET_BOOL, NO_ARG, 0, 0, 0,
575
    0, 0, 0},
576
  {"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
577
    (char**) &commit_rate, (char**) &commit_rate, 0, GET_UINT, REQUIRED_ARG,
1 by brian
clean slate
578
    0, 0, 0, 0, 0, 0},
579
  {"compress", 'C', "Use compression in server/client protocol.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
580
    (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1 by brian
clean slate
581
    0, 0, 0},
582
  {"concurrency", 'c', "Number of clients to simulate for query to run.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
583
    (char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
1 by brian
clean slate
584
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
585
  {"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
586
    (char**) &create_string, (char**) &create_string, 0, GET_STR, REQUIRED_ARG,
1 by brian
clean slate
587
    0, 0, 0, 0, 0, 0},
588
  {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
589
    (char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR, 
1 by brian
clean slate
590
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
591
  {"csv", OPT_SLAP_CSV,
592
	"Generate CSV output to named file or to stdout if no file is named.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
593
    (char**) &opt_csv_str, (char**) &opt_csv_str, 0, GET_STR, 
1 by brian
clean slate
594
    OPT_ARG, 0, 0, 0, 0, 0, 0},
595
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
596
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
1 by brian
clean slate
597
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
598
  {"debug-info", 'T', "Print some debug info at exit.", (char**) &debug_info_flag,
599
   (char**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
600
  {"delayed-start", OPT_SLAP_DELAYED_START, 
601
    "Delay the startup of threads by a random number of microsends (the maximum of the delay)",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
602
    (char**) &opt_delayed_start, (char**) &opt_delayed_start, 0, GET_UINT, 
1 by brian
clean slate
603
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
604
  {"delimiter", 'F',
605
    "Delimiter to use in SQL statements supplied in file or command line.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
606
    (char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
1 by brian
clean slate
607
    0, 0, 0, 0, 0, 0},
608
  {"detach", OPT_SLAP_DETACH,
609
    "Detach (close and reopen) connections after X number of requests.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
610
    (char**) &detach_rate, (char**) &detach_rate, 0, GET_UINT, REQUIRED_ARG, 
1 by brian
clean slate
611
    0, 0, 0, 0, 0, 0},
612
  {"engine", 'e', "Storage engine to use for creating the table.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
613
    (char**) &default_engine, (char**) &default_engine, 0,
1 by brian
clean slate
614
    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
615
  {"host", 'h', "Connect to host.", (char**) &host, (char**) &host, 0, GET_STR,
1 by brian
clean slate
616
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
617
  {"iterations", 'i', "Number of times to run the tests.", (char**) &iterations,
618
    (char**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
1 by brian
clean slate
619
  {"label", OPT_SLAP_LABEL, "Label to use for print and csv output.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
620
    (char**) &opt_label, (char**) &opt_label, 0,
1 by brian
clean slate
621
    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
622
  {"number-blob-cols", OPT_SLAP_BLOB_COL, 
623
    "Number of BLOB columns to create table with if specifying --auto-generate-sql. Example --number-blob-cols=3:1024/2048 would give you 3 blobs with a random size between 1024 and 2048. ",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
624
    (char**) &num_blob_cols_opt, (char**) &num_blob_cols_opt, 0, GET_STR, REQUIRED_ARG,
1 by brian
clean slate
625
    0, 0, 0, 0, 0, 0},
626
  {"number-char-cols", 'x', 
627
    "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
628
    (char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
1 by brian
clean slate
629
    0, 0, 0, 0, 0, 0},
630
  {"number-int-cols", 'y', 
631
    "Number of INT columns to create in table if specifying --auto-generate-sql.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
632
    (char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG, 
1 by brian
clean slate
633
    0, 0, 0, 0, 0, 0},
634
  {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY, 
635
    "Limit each client to this number of queries (this is not exact).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
636
    (char**) &num_of_query, (char**) &num_of_query, 0,
1 by brian
clean slate
637
    GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
638
  {"only-print", OPT_MYSQL_ONLY_PRINT,
639
    "This causes mysqlslap to not connect to the databases, but instead print "
640
      "out what it would have done instead.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
641
    (char**) &opt_only_print, (char**) &opt_only_print, 0, GET_BOOL,  NO_ARG,
1 by brian
clean slate
642
    0, 0, 0, 0, 0, 0},
643
  {"password", 'p',
644
    "Password to use when connecting to server. If password is not given it's "
645
      "asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
646
  {"port", 'P', "Port number to use for connection.", (char**) &opt_mysql_port,
647
    (char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
1 by brian
clean slate
648
    0},
649
  {"post-query", OPT_SLAP_POST_QUERY,
650
    "Query to run or file containing query to execute after tests have completed.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
651
    (char**) &user_supplied_post_statements, 
652
    (char**) &user_supplied_post_statements,
1 by brian
clean slate
653
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
654
  {"post-system", OPT_SLAP_POST_SYSTEM,
655
    "system() string to execute after tests have completed.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
656
    (char**) &post_system, 
657
    (char**) &post_system,
1 by brian
clean slate
658
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
659
  {"pre-query", OPT_SLAP_PRE_QUERY, 
660
    "Query to run or file containing query to execute before running tests.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
661
    (char**) &user_supplied_pre_statements, 
662
    (char**) &user_supplied_pre_statements,
1 by brian
clean slate
663
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
664
  {"pre-system", OPT_SLAP_PRE_SYSTEM, 
665
    "system() string to execute before running tests.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
666
    (char**) &pre_system, 
667
    (char**) &pre_system,
1 by brian
clean slate
668
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
669
  {"protocol", OPT_MYSQL_PROTOCOL,
670
    "The protocol of connection (tcp,socket,pipe,memory).",
671
    0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
672
  {"query", 'q', "Query to run or file containing query to run.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
673
    (char**) &user_supplied_query, (char**) &user_supplied_query,
1 by brian
clean slate
674
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
675
  {"set-random-seed", OPT_SLAP_SET_RANDOM_SEED, 
676
    "Seed for random number generator (srandom(3))",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
677
    (char**)&opt_set_random_seed,
678
    (char**)&opt_set_random_seed,0,
1 by brian
clean slate
679
    GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
680
#ifdef HAVE_SMEM
681
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
682
    "Base name of shared memory.", (char**) &shared_memory_base_name,
683
    (char**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
1 by brian
clean slate
684
    0, 0, 0, 0, 0, 0},
685
#endif
686
  {"silent", 's', "Run program in silent mode - no output.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
687
    (char**) &opt_silent, (char**) &opt_silent, 0, GET_BOOL,  NO_ARG,
1 by brian
clean slate
688
    0, 0, 0, 0, 0, 0},
689
  {"socket", 'S', "Socket file to use for connection.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
690
    (char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR,
1 by brian
clean slate
691
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
692
  {"timer-length", OPT_SLAP_TIMER_LENGTH, 
693
    "Require mysqlslap to run each specific test a certain amount of time in seconds.", 
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
694
    (char**) &opt_timer_length, (char**) &opt_timer_length, 0, GET_UINT, 
1 by brian
clean slate
695
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
696
#ifndef DONT_ALLOW_USER_CHANGE
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
697
  {"user", 'u', "User for login if not current user.", (char**) &user,
698
    (char**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
699
#endif
700
  {"verbose", 'v',
701
    "More verbose output; you can use this multiple times to get even more "
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
702
      "verbose output.", (char**) &verbose, (char**) &verbose, 0, 
1 by brian
clean slate
703
      GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
704
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
705
    NO_ARG, 0, 0, 0, 0, 0, 0},
706
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
707
};
708
709
710
#include <help_start.h>
711
712
static void print_version(void)
713
{
714
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
715
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
716
}
717
718
719
static void usage(void)
720
{
721
  print_version();
722
  puts("Copyright (C) 2005 MySQL AB");
723
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
724
       \nand you are welcome to modify and redistribute it under the GPL \
725
       license\n");
726
  puts("Run a query multiple times against the server\n");
727
  printf("Usage: %s [OPTIONS]\n",my_progname);
728
  print_defaults("my",load_default_groups);
729
  my_print_help(my_long_options);
730
}
731
732
#include <help_end.h>
733
143 by Brian Aker
Bool cleanup.
734
static bool
1 by brian
clean slate
735
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
736
               char *argument)
737
{
142.1.2 by Patrick
All DBUG_x removed from client/
738
1 by brian
clean slate
739
  switch(optid) {
740
  case 'v':
741
    verbose++;
742
    break;
743
  case 'p':
744
    if (argument)
745
    {
746
      char *start= argument;
747
      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
748
      opt_password= my_strdup(argument,MYF(MY_FAE));
749
      while (*argument) *argument++= 'x';		/* Destroy argument */
750
      if (*start)
751
        start[1]= 0;				/* Cut length of argument */
752
      tty_password= 0;
753
    }
754
    else
755
      tty_password= 1;
756
    break;
757
  case 'V':
758
    print_version();
759
    exit(0);
760
    break;
761
  case '?':
762
  case 'I':					/* Info */
763
    usage();
764
    exit(0);
765
  }
142.1.2 by Patrick
All DBUG_x removed from client/
766
  return(0);
1 by brian
clean slate
767
}
768
769
770
uint
771
get_random_string(char *buf, size_t size)
772
{
773
  char *buf_ptr= buf;
774
  size_t x;
142.1.2 by Patrick
All DBUG_x removed from client/
775
1 by brian
clean slate
776
  for (x= size; x > 0; x--)
777
    *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
142.1.2 by Patrick
All DBUG_x removed from client/
778
  return(buf_ptr - buf);
1 by brian
clean slate
779
}
780
781
782
/*
783
  build_table_string
784
785
  This function builds a create table query if the user opts to not supply
786
  a file or string containing a create table statement
787
*/
788
static statement *
789
build_table_string(void)
790
{
791
  char       buf[HUGE_STRING_LENGTH];
792
  unsigned int        col_count;
793
  statement *ptr;
794
  DYNAMIC_STRING table_string;
795
796
  init_dynamic_string(&table_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
797
798
  dynstr_append(&table_string, "CREATE TABLE `t1` (");
799
800
  if (auto_generate_sql_autoincrement)
801
  {
802
    dynstr_append(&table_string, "id serial");
803
804
    if (num_int_cols || num_char_cols)
805
      dynstr_append(&table_string, ",");
806
  }
807
808
  if (auto_generate_sql_guid_primary)
809
  {
810
    dynstr_append(&table_string, "id varchar(128) primary key");
811
812
    if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
813
      dynstr_append(&table_string, ",");
814
  }
815
816
  if (auto_generate_sql_secondary_indexes)
817
  {
818
    unsigned int count;
819
820
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
821
    {
822
      if (count) /* Except for the first pass we add a comma */
823
        dynstr_append(&table_string, ",");
824
825
      if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count) 
826
          > HUGE_STRING_LENGTH)
827
      {
828
        fprintf(stderr, "Memory Allocation error in create table\n");
829
        exit(1);
830
      }
831
      dynstr_append(&table_string, buf);
832
    }
833
834
    if (num_int_cols || num_char_cols)
835
      dynstr_append(&table_string, ",");
836
  }
837
838
  if (num_int_cols)
839
    for (col_count= 1; col_count <= num_int_cols; col_count++)
840
    {
841
      if (num_int_cols_index)
842
      {
843
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)", 
844
                     col_count, col_count) > HUGE_STRING_LENGTH)
845
        {
846
          fprintf(stderr, "Memory Allocation error in create table\n");
847
          exit(1);
848
        }
849
      }
850
      else
851
      {
852
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count) 
853
            > HUGE_STRING_LENGTH)
854
        {
855
          fprintf(stderr, "Memory Allocation error in create table\n");
856
          exit(1);
857
        }
858
      }
859
      dynstr_append(&table_string, buf);
860
861
      if (col_count < num_int_cols || num_char_cols > 0)
862
        dynstr_append(&table_string, ",");
863
    }
864
865
  if (num_char_cols)
866
    for (col_count= 1; col_count <= num_char_cols; col_count++)
867
    {
868
      if (num_char_cols_index)
869
      {
870
        if (snprintf(buf, HUGE_STRING_LENGTH, 
871
                     "charcol%d VARCHAR(128), INDEX(charcol%d) ", 
872
                     col_count, col_count) > HUGE_STRING_LENGTH)
873
        {
874
          fprintf(stderr, "Memory Allocation error in creating table\n");
875
          exit(1);
876
        }
877
      }
878
      else
879
      {
880
        if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)", 
881
                     col_count) > HUGE_STRING_LENGTH)
882
        {
883
          fprintf(stderr, "Memory Allocation error in creating table\n");
884
          exit(1);
885
        }
886
      }
887
      dynstr_append(&table_string, buf);
888
889
      if (col_count < num_char_cols || num_blob_cols > 0)
890
        dynstr_append(&table_string, ",");
891
    }
892
893
  if (num_blob_cols)
894
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
895
    {
896
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob", 
897
                   col_count) > HUGE_STRING_LENGTH)
898
      {
899
        fprintf(stderr, "Memory Allocation error in creating table\n");
900
        exit(1);
901
      }
902
      dynstr_append(&table_string, buf);
903
904
      if (col_count < num_blob_cols)
905
        dynstr_append(&table_string, ",");
906
    }
907
908
  dynstr_append(&table_string, ")");
909
  ptr= (statement *)my_malloc(sizeof(statement), 
910
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
911
  ptr->string = (char *)my_malloc(table_string.length+1,
912
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
913
  ptr->length= table_string.length+1;
914
  ptr->type= CREATE_TABLE_TYPE;
915
  strmov(ptr->string, table_string.str);
916
  dynstr_free(&table_string);
142.1.2 by Patrick
All DBUG_x removed from client/
917
  return(ptr);
1 by brian
clean slate
918
}
919
920
/*
921
  build_update_string()
922
923
  This function builds insert statements when the user opts to not supply
924
  an insert file or string containing insert data
925
*/
926
static statement *
927
build_update_string(void)
928
{
929
  char       buf[HUGE_STRING_LENGTH];
930
  unsigned int        col_count;
931
  statement *ptr;
932
  DYNAMIC_STRING update_string;
142.1.2 by Patrick
All DBUG_x removed from client/
933
1 by brian
clean slate
934
935
  init_dynamic_string(&update_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
936
937
  dynstr_append(&update_string, "UPDATE t1 SET ");
938
939
  if (num_int_cols)
940
    for (col_count= 1; col_count <= num_int_cols; col_count++)
941
    {
942
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count, 
943
                   random()) > HUGE_STRING_LENGTH)
944
      {
945
        fprintf(stderr, "Memory Allocation error in creating update\n");
946
        exit(1);
947
      }
948
      dynstr_append(&update_string, buf);
949
950
      if (col_count < num_int_cols || num_char_cols > 0)
951
        dynstr_append_mem(&update_string, ",", 1);
952
    }
953
954
  if (num_char_cols)
955
    for (col_count= 1; col_count <= num_char_cols; col_count++)
956
    {
957
      char rand_buffer[RAND_STRING_SIZE];
958
      int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
959
960
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count, 
961
                   buf_len, rand_buffer) 
962
          > HUGE_STRING_LENGTH)
963
      {
964
        fprintf(stderr, "Memory Allocation error in creating update\n");
965
        exit(1);
966
      }
967
      dynstr_append(&update_string, buf);
968
969
      if (col_count < num_char_cols)
970
        dynstr_append_mem(&update_string, ",", 1);
971
    }
972
973
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
974
    dynstr_append(&update_string, " WHERE id = ");
975
976
977
  ptr= (statement *)my_malloc(sizeof(statement), 
978
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
979
980
  ptr->string= (char *)my_malloc(update_string.length + 1,
981
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
982
  ptr->length= update_string.length+1;
983
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
984
    ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
985
  else
986
    ptr->type= UPDATE_TYPE;
987
  strmov(ptr->string, update_string.str);
988
  dynstr_free(&update_string);
142.1.2 by Patrick
All DBUG_x removed from client/
989
  return(ptr);
1 by brian
clean slate
990
}
991
992
993
/*
994
  build_insert_string()
995
996
  This function builds insert statements when the user opts to not supply
997
  an insert file or string containing insert data
998
*/
999
static statement *
1000
build_insert_string(void)
1001
{
1002
  char       buf[HUGE_STRING_LENGTH];
1003
  unsigned int        col_count;
1004
  statement *ptr;
1005
  DYNAMIC_STRING insert_string;
142.1.2 by Patrick
All DBUG_x removed from client/
1006
1 by brian
clean slate
1007
1008
  init_dynamic_string(&insert_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
1009
1010
  dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
1011
1012
  if (auto_generate_sql_autoincrement)
1013
  {
1014
    dynstr_append(&insert_string, "NULL");
1015
1016
    if (num_int_cols || num_char_cols)
1017
      dynstr_append(&insert_string, ",");
1018
  }
1019
1020
  if (auto_generate_sql_guid_primary)
1021
  {
1022
    dynstr_append(&insert_string, "uuid()");
1023
1024
    if (num_int_cols || num_char_cols)
1025
      dynstr_append(&insert_string, ",");
1026
  }
1027
1028
  if (auto_generate_sql_secondary_indexes)
1029
  {
1030
    unsigned int count;
1031
1032
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1033
    {
1034
      if (count) /* Except for the first pass we add a comma */
1035
        dynstr_append(&insert_string, ",");
1036
1037
      dynstr_append(&insert_string, "uuid()");
1038
    }
1039
1040
    if (num_int_cols || num_char_cols)
1041
      dynstr_append(&insert_string, ",");
1042
  }
1043
1044
  if (num_int_cols)
1045
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1046
    {
1047
      if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1048
      {
1049
        fprintf(stderr, "Memory Allocation error in creating insert\n");
1050
        exit(1);
1051
      }
1052
      dynstr_append(&insert_string, buf);
1053
1054
      if (col_count < num_int_cols || num_char_cols > 0)
1055
        dynstr_append_mem(&insert_string, ",", 1);
1056
    }
1057
1058
  if (num_char_cols)
1059
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1060
    {
1061
      int buf_len= get_random_string(buf, RAND_STRING_SIZE);
1062
      dynstr_append_mem(&insert_string, "'", 1);
1063
      dynstr_append_mem(&insert_string, buf, buf_len);
1064
      dynstr_append_mem(&insert_string, "'", 1);
1065
1066
      if (col_count < num_char_cols || num_blob_cols > 0)
1067
        dynstr_append_mem(&insert_string, ",", 1);
1068
    }
1069
1070
  if (num_blob_cols)
1071
  {
1072
    char *blob_ptr;
1073
1074
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
1075
    {
1076
      blob_ptr= (char *)my_malloc(sizeof(char)*num_blob_cols_size,
1077
                             MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1078
      if (!blob_ptr)
1079
      {
1080
        fprintf(stderr, "Memory Allocation error in creating select\n");
1081
        exit(1);
1082
      }
1083
    }
1084
    else
1085
    {
1086
      blob_ptr= buf;
1087
    }
1088
1089
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1090
    {
1091
      unsigned int buf_len;
1092
      unsigned int size;
1093
      unsigned int difference= num_blob_cols_size - num_blob_cols_size_min;
1094
1095
      size= difference ? (num_blob_cols_size_min + (random() % difference)) : 
1096
                          num_blob_cols_size;
1097
1098
      buf_len= get_random_string(blob_ptr, size);
1099
1100
      dynstr_append_mem(&insert_string, "'", 1);
1101
      dynstr_append_mem(&insert_string, blob_ptr, buf_len);
1102
      dynstr_append_mem(&insert_string, "'", 1);
1103
1104
      if (col_count < num_blob_cols)
1105
        dynstr_append_mem(&insert_string, ",", 1);
1106
    }
1107
1108
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
1109
      my_free(blob_ptr, MYF(0));
1110
  }
1111
1112
  dynstr_append_mem(&insert_string, ")", 1);
1113
1114
  if (!(ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL|MY_FAE|MY_WME))))
1115
  {
1116
    fprintf(stderr, "Memory Allocation error in creating select\n");
1117
    exit(1);
1118
  }
1119
  if (!(ptr->string= (char *)my_malloc(insert_string.length + 1, MYF(MY_ZEROFILL|MY_FAE|MY_WME))))
1120
  {
1121
    fprintf(stderr, "Memory Allocation error in creating select\n");
1122
    exit(1);
1123
  }
1124
  ptr->length= insert_string.length+1;
1125
  ptr->type= INSERT_TYPE;
1126
  strmov(ptr->string, insert_string.str);
1127
  dynstr_free(&insert_string);
1128
142.1.2 by Patrick
All DBUG_x removed from client/
1129
  return(ptr);
1 by brian
clean slate
1130
}
1131
1132
1133
/*
1134
  build_select_string()
1135
1136
  This function builds a query if the user opts to not supply a query
1137
  statement or file containing a query statement
1138
*/
1139
static statement *
143 by Brian Aker
Bool cleanup.
1140
build_select_string(bool key)
1 by brian
clean slate
1141
{
1142
  char       buf[HUGE_STRING_LENGTH];
1143
  unsigned int        col_count;
1144
  statement *ptr;
1145
  static DYNAMIC_STRING query_string;
142.1.2 by Patrick
All DBUG_x removed from client/
1146
1 by brian
clean slate
1147
1148
  init_dynamic_string(&query_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
1149
1150
  dynstr_append_mem(&query_string, "SELECT ", 7);
1151
  if (auto_generate_selected_columns_opt)
1152
  {
1153
    dynstr_append(&query_string, auto_generate_selected_columns_opt);
1154
  }
1155
  else
1156
  {
1157
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1158
    {
1159
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count) 
1160
          > HUGE_STRING_LENGTH)
1161
      {
1162
        fprintf(stderr, "Memory Allocation error in creating select\n");
1163
        exit(1);
1164
      }
1165
      dynstr_append(&query_string, buf);
1166
1167
      if (col_count < num_int_cols || num_char_cols > 0)
1168
        dynstr_append_mem(&query_string, ",", 1);
1169
1170
    }
1171
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1172
    {
1173
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1174
          > HUGE_STRING_LENGTH)
1175
      {
1176
        fprintf(stderr, "Memory Allocation error in creating select\n");
1177
        exit(1);
1178
      }
1179
      dynstr_append(&query_string, buf);
1180
1181
      if (col_count < num_char_cols || num_blob_cols > 0)
1182
        dynstr_append_mem(&query_string, ",", 1);
1183
1184
    }
1185
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1186
    {
1187
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
1188
          > HUGE_STRING_LENGTH)
1189
      {
1190
        fprintf(stderr, "Memory Allocation error in creating select\n");
1191
        exit(1);
1192
      }
1193
      dynstr_append(&query_string, buf);
1194
1195
      if (col_count < num_blob_cols)
1196
        dynstr_append_mem(&query_string, ",", 1);
1197
    }
1198
  }
1199
  dynstr_append(&query_string, " FROM t1");
1200
1201
  if ((key) && 
1202
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1203
    dynstr_append(&query_string, " WHERE id = ");
1204
1205
  ptr= (statement *)my_malloc(sizeof(statement),
1206
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1207
  ptr->string= (char *)my_malloc(query_string.length + 1,
1208
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1209
  ptr->length= query_string.length+1;
1210
  if ((key) && 
1211
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1212
    ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1213
  else
1214
    ptr->type= SELECT_TYPE;
1215
  strmov(ptr->string, query_string.str);
1216
  dynstr_free(&query_string);
142.1.2 by Patrick
All DBUG_x removed from client/
1217
  return(ptr);
1 by brian
clean slate
1218
}
1219
1220
static int
1221
get_options(int *argc,char ***argv)
1222
{
1223
  int ho_error;
1224
  char *tmp_string;
15 by brian
Fix for stat, NETWARE removal
1225
  struct stat sbuf;
1 by brian
clean slate
1226
  option_string *sql_type;
1227
  unsigned int sql_type_count= 0;
1228
142.1.2 by Patrick
All DBUG_x removed from client/
1229
1 by brian
clean slate
1230
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1231
    exit(ho_error);
1232
  if (debug_info_flag)
1233
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1234
  if (debug_check_flag)
1235
    my_end_arg= MY_CHECK_ERROR;
1236
1237
  if (!user)
1238
    user= (char *)"root";
1239
1240
  /* If something is created we clean it up, otherwise we leave schemas alone */
1241
  if (create_string || auto_generate_sql)
163 by Brian Aker
Merge Monty's code.
1242
    opt_preserve= false;
1 by brian
clean slate
1243
1244
  if (auto_generate_sql && (create_string || user_supplied_query))
1245
  {
1246
      fprintf(stderr,
1247
              "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1248
              my_progname);
1249
      exit(1);
1250
  }
1251
1252
  if (auto_generate_sql && auto_generate_sql_guid_primary && 
1253
      auto_generate_sql_autoincrement)
1254
  {
1255
      fprintf(stderr,
1256
              "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1257
              my_progname);
1258
      exit(1);
1259
  }
1260
1261
  if (auto_generate_sql && num_of_query && auto_actual_queries)
1262
  {
1263
      fprintf(stderr,
1264
              "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1265
              my_progname);
1266
      exit(1);
1267
  }
1268
1269
  parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1270
1271
  if (opt_csv_str)
1272
  {
163 by Brian Aker
Merge Monty's code.
1273
    opt_silent= true;
1 by brian
clean slate
1274
    
1275
    if (opt_csv_str[0] == '-')
1276
    {
1277
      csv_file= fileno(stdout);
1278
    }
1279
    else
1280
    {
1281
      if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1282
          == -1)
1283
      {
1284
        fprintf(stderr,"%s: Could not open csv file: %sn\n",
1285
                my_progname, opt_csv_str);
1286
        exit(1);
1287
      }
1288
    }
1289
  }
1290
1291
  if (opt_only_print)
163 by Brian Aker
Merge Monty's code.
1292
    opt_silent= true;
1 by brian
clean slate
1293
1294
  if (num_int_cols_opt)
1295
  {
1296
    option_string *str;
1297
    parse_option(num_int_cols_opt, &str, ',');
1298
    num_int_cols= atoi(str->string);
1299
    if (str->option)
1300
      num_int_cols_index= atoi(str->option);
1301
    option_cleanup(str);
1302
  }
1303
1304
  if (num_char_cols_opt)
1305
  {
1306
    option_string *str;
1307
    parse_option(num_char_cols_opt, &str, ',');
1308
    num_char_cols= atoi(str->string);
1309
    if (str->option)
1310
      num_char_cols_index= atoi(str->option);
1311
    else
1312
      num_char_cols_index= 0;
1313
    option_cleanup(str);
1314
  }
1315
1316
  if (num_blob_cols_opt)
1317
  {
1318
    option_string *str;
1319
    parse_option(num_blob_cols_opt, &str, ',');
1320
    num_blob_cols= atoi(str->string);
1321
    if (str->option)
1322
    {
1323
      char *sep_ptr;
1324
1325
      if ((sep_ptr= strchr(str->option, '/')))
1326
      {
1327
        num_blob_cols_size_min= atoi(str->option);
1328
        num_blob_cols_size= atoi(sep_ptr+1);
1329
      }
1330
      else
1331
      {
1332
        num_blob_cols_size_min= num_blob_cols_size= atoi(str->option);
1333
      }
1334
    }
1335
    else
1336
    {
1337
      num_blob_cols_size= DEFAULT_BLOB_SIZE;
1338
      num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
1339
    }
1340
    option_cleanup(str);
1341
  }
1342
1343
1344
  if (auto_generate_sql)
1345
  {
1346
    unsigned long long x= 0;
1347
    statement *ptr_statement;
1348
1349
    if (verbose >= 2)
1350
      printf("Building Create Statements for Auto\n");
1351
1352
    create_statements= build_table_string();
1353
    /* 
1354
      Pre-populate table 
1355
    */
1356
    for (ptr_statement= create_statements, x= 0; 
1357
         x < auto_generate_sql_unique_write_number; 
1358
         x++, ptr_statement= ptr_statement->next)
1359
    {
1360
      ptr_statement->next= build_insert_string();
1361
    }
1362
1363
    if (verbose >= 2)
1364
      printf("Building Query Statements for Auto\n");
1365
1366
    if (!opt_auto_generate_sql_type)
1367
      opt_auto_generate_sql_type= "mixed";
1368
1369
    query_statements_count= 
1370
      parse_option(opt_auto_generate_sql_type, &query_options, ',');
1371
1372
    query_statements= (statement **)my_malloc(sizeof(statement *) * query_statements_count,
1373
                                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1374
1375
    sql_type= query_options;
1376
    do
1377
    {
1378
      if (sql_type->string[0] == 'r')
1379
      {
1380
        if (verbose >= 2)
1381
          printf("Generating SELECT Statements for Auto\n");
1382
163 by Brian Aker
Merge Monty's code.
1383
        query_statements[sql_type_count]= build_select_string(false);
1 by brian
clean slate
1384
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1385
             x < auto_generate_sql_unique_query_number; 
1386
             x++, ptr_statement= ptr_statement->next)
1387
        {
163 by Brian Aker
Merge Monty's code.
1388
          ptr_statement->next= build_select_string(false);
1 by brian
clean slate
1389
        }
1390
      }
1391
      else if (sql_type->string[0] == 'k')
1392
      {
1393
        if (verbose >= 2)
1394
          printf("Generating SELECT for keys Statements for Auto\n");
1395
163 by Brian Aker
Merge Monty's code.
1396
        if ( auto_generate_sql_autoincrement == false &&
1397
             auto_generate_sql_guid_primary == false)
1 by brian
clean slate
1398
        {
1399
          fprintf(stderr,
1400
                  "%s: Can't perform key test without a primary key!\n",
1401
                  my_progname);
1402
          exit(1);
1403
        }
1404
163 by Brian Aker
Merge Monty's code.
1405
        query_statements[sql_type_count]= build_select_string(true);
1 by brian
clean slate
1406
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1407
             x < auto_generate_sql_unique_query_number; 
1408
             x++, ptr_statement= ptr_statement->next)
1409
        {
163 by Brian Aker
Merge Monty's code.
1410
          ptr_statement->next= build_select_string(true);
1 by brian
clean slate
1411
        }
1412
      }
1413
      else if (sql_type->string[0] == 'w')
1414
      {
1415
        /*
1416
          We generate a number of strings in case the engine is 
1417
          Archive (since strings which were identical one after another
1418
          would be too easily optimized).
1419
        */
1420
        if (verbose >= 2)
1421
          printf("Generating INSERT Statements for Auto\n");
1422
        query_statements[sql_type_count]= build_insert_string();
1423
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1424
             x < auto_generate_sql_unique_query_number; 
1425
             x++, ptr_statement= ptr_statement->next)
1426
        {
1427
          ptr_statement->next= build_insert_string();
1428
        }
1429
      }
1430
      else if (sql_type->string[0] == 'u')
1431
      {
163 by Brian Aker
Merge Monty's code.
1432
        if ( auto_generate_sql_autoincrement == false &&
1433
             auto_generate_sql_guid_primary == false)
1 by brian
clean slate
1434
        {
1435
          fprintf(stderr,
1436
                  "%s: Can't perform update test without a primary key!\n",
1437
                  my_progname);
1438
          exit(1);
1439
        }
1440
1441
        query_statements[sql_type_count]= build_update_string();
1442
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1443
             x < auto_generate_sql_unique_query_number; 
1444
             x++, ptr_statement= ptr_statement->next)
1445
        {
1446
          ptr_statement->next= build_update_string();
1447
        }
1448
      }
1449
      else /* Mixed mode is default */
1450
      {
1451
        int coin= 0;
1452
1453
        query_statements[sql_type_count]= build_insert_string();
1454
        /* 
1455
          This logic should be extended to do a more mixed load,
1456
          at the moment it results in "every other".
1457
        */
1458
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1459
             x < auto_generate_sql_unique_query_number; 
1460
             x++, ptr_statement= ptr_statement->next)
1461
        {
1462
          if (coin)
1463
          {
1464
            ptr_statement->next= build_insert_string();
1465
            coin= 0;
1466
          }
1467
          else
1468
          {
163 by Brian Aker
Merge Monty's code.
1469
            ptr_statement->next= build_select_string(true);
1 by brian
clean slate
1470
            coin= 1;
1471
          }
1472
        }
1473
      }
1474
      sql_type_count++;
1475
    } while (sql_type ? (sql_type= sql_type->next) : 0);
1476
  }
1477
  else
1478
  {
15 by brian
Fix for stat, NETWARE removal
1479
    if (create_string && !stat(create_string, &sbuf))
1 by brian
clean slate
1480
    {
1481
      File data_file;
1482
      if (!MY_S_ISREG(sbuf.st_mode))
1483
      {
1484
        fprintf(stderr,"%s: Create file was not a regular file\n",
1485
                my_progname);
1486
        exit(1);
1487
      }
1488
      if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1489
      {
1490
        fprintf(stderr,"%s: Could not open create file\n", my_progname);
1491
        exit(1);
1492
      }
1493
      tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1494
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1495
      my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1496
      tmp_string[sbuf.st_size]= '\0';
1497
      my_close(data_file,MYF(0));
1498
      parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1499
      my_free(tmp_string, MYF(0));
1500
    }
1501
    else if (create_string)
1502
    {
1503
        parse_delimiter(create_string, &create_statements, delimiter[0]);
1504
    }
1505
1506
    /* Set this up till we fully support options on user generated queries */
1507
    if (user_supplied_query)
1508
    {
1509
      query_statements_count= 
1510
        parse_option("default", &query_options, ',');
1511
1512
      query_statements= (statement **)my_malloc(sizeof(statement *),
1513
                                                MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1514
    }
1515
15 by brian
Fix for stat, NETWARE removal
1516
    if (user_supplied_query && !stat(user_supplied_query, &sbuf))
1 by brian
clean slate
1517
    {
1518
      File data_file;
1519
      if (!MY_S_ISREG(sbuf.st_mode))
1520
      {
1521
        fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1522
                my_progname);
1523
        exit(1);
1524
      }
1525
      if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1526
      {
1527
        fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1528
        exit(1);
1529
      }
1530
      tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1531
                                    MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1532
      my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1533
      tmp_string[sbuf.st_size]= '\0';
1534
      my_close(data_file,MYF(0));
1535
      if (user_supplied_query)
1536
        actual_queries= parse_delimiter(tmp_string, &query_statements[0],
1537
                                        delimiter[0]);
1538
      my_free(tmp_string, MYF(0));
1539
    } 
1540
    else if (user_supplied_query)
1541
    {
1542
      actual_queries= parse_delimiter(user_supplied_query, &query_statements[0],
1543
                                      delimiter[0]);
1544
    }
1545
  }
1546
15 by brian
Fix for stat, NETWARE removal
1547
  if (user_supplied_pre_statements
1548
      && !stat(user_supplied_pre_statements, &sbuf))
1 by brian
clean slate
1549
  {
1550
    File data_file;
1551
    if (!MY_S_ISREG(sbuf.st_mode))
1552
    {
1553
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1554
              my_progname);
1555
      exit(1);
1556
    }
1557
    if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1558
    {
1559
      fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1560
      exit(1);
1561
    }
1562
    tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1563
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1564
    my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1565
    tmp_string[sbuf.st_size]= '\0';
1566
    my_close(data_file,MYF(0));
1567
    if (user_supplied_pre_statements)
1568
      (void)parse_delimiter(tmp_string, &pre_statements,
1569
                            delimiter[0]);
1570
    my_free(tmp_string, MYF(0));
1571
  } 
1572
  else if (user_supplied_pre_statements)
1573
  {
1574
    (void)parse_delimiter(user_supplied_pre_statements,
1575
                          &pre_statements,
1576
                          delimiter[0]);
1577
  }
1578
15 by brian
Fix for stat, NETWARE removal
1579
  if (user_supplied_post_statements
1580
      && !stat(user_supplied_post_statements, &sbuf))
1 by brian
clean slate
1581
  {
1582
    File data_file;
1583
    if (!MY_S_ISREG(sbuf.st_mode))
1584
    {
1585
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1586
              my_progname);
1587
      exit(1);
1588
    }
1589
    if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1590
    {
1591
      fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1592
      exit(1);
1593
    }
1594
    tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1595
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1596
    my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1597
    tmp_string[sbuf.st_size]= '\0';
1598
    my_close(data_file,MYF(0));
1599
    if (user_supplied_post_statements)
1600
      (void)parse_delimiter(tmp_string, &post_statements,
1601
                            delimiter[0]);
1602
    my_free(tmp_string, MYF(0));
1603
  } 
1604
  else if (user_supplied_post_statements)
1605
  {
1606
    (void)parse_delimiter(user_supplied_post_statements, &post_statements,
1607
                          delimiter[0]);
1608
  }
1609
1610
  if (verbose >= 2)
1611
    printf("Parsing engines to use.\n");
1612
1613
  if (default_engine)
1614
    parse_option(default_engine, &engine_options, ',');
1615
1616
  if (tty_password)
1617
    opt_password= get_tty_password(NullS);
142.1.2 by Patrick
All DBUG_x removed from client/
1618
  return(0);
1 by brian
clean slate
1619
}
1620
1621
1622
static int run_query(MYSQL *mysql, const char *query, int len)
1623
{
1624
  if (opt_only_print)
1625
  {
1626
    printf("%.*s;\n", len, query);
1627
    return 0;
1628
  }
1629
1630
  if (verbose >= 3)
1631
    printf("%.*s;\n", len, query);
1632
  return mysql_real_query(mysql, query, len);
1633
}
1634
1635
1636
static int
1637
generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1638
{
1639
  MYSQL_RES *result;
1640
  MYSQL_ROW row;
1641
  unsigned long long counter;
142.1.2 by Patrick
All DBUG_x removed from client/
1642
1 by brian
clean slate
1643
1644
  /* 
1645
    Blackhole is a special case, this allows us to test the upper end 
1646
    of the server during load runs.
1647
  */
1648
  if (opt_only_print || (engine_stmt && 
1649
                         strstr(engine_stmt->string, "blackhole")))
1650
  {
1651
    primary_keys_number_of= 1;
1652
    primary_keys= (char **)my_malloc((uint)(sizeof(char *) * 
1653
                                            primary_keys_number_of), 
1654
                                    MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1655
    /* Yes, we strdup a const string to simplify the interface */
1656
    primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0)); 
1657
  }
1658
  else
1659
  {
1660
    if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1661
    {
1662
      fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1663
              mysql_error(mysql));
1664
      exit(1);
1665
    }
1666
1667
    result= mysql_store_result(mysql);
1668
    primary_keys_number_of= mysql_num_rows(result);
1669
1670
    /* So why check this? Blackhole :) */
1671
    if (primary_keys_number_of)
1672
    {
1673
      /*
1674
        We create the structure and loop and create the items.
1675
      */
1676
      primary_keys= (char **)my_malloc((uint)(sizeof(char *) * 
1677
                                              primary_keys_number_of), 
1678
                                       MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1679
      row= mysql_fetch_row(result);
1680
      for (counter= 0; counter < primary_keys_number_of; 
1681
           counter++, row= mysql_fetch_row(result))
1682
        primary_keys[counter]= my_strdup(row[0], MYF(0));
1683
    }
1684
1685
    mysql_free_result(result);
1686
  }
1687
142.1.2 by Patrick
All DBUG_x removed from client/
1688
  return(0);
1 by brian
clean slate
1689
}
1690
1691
static int
1692
drop_primary_key_list(void)
1693
{
1694
  unsigned long long counter;
1695
1696
  if (primary_keys_number_of)
1697
  {
1698
    for (counter= 0; counter < primary_keys_number_of; counter++)
1699
      my_free(primary_keys[counter], MYF(0));
1700
1701
    my_free(primary_keys, MYF(0));
1702
  }
1703
1704
  return 0;
1705
}
1706
1707
static int
1708
create_schema(MYSQL *mysql, const char *db, statement *stmt, 
1709
              option_string *engine_stmt, stats *sptr)
1710
{
1711
  char query[HUGE_STRING_LENGTH];
1712
  statement *ptr;
1713
  statement *after_create;
1714
  int len;
151 by Brian Aker
Ulonglong to uint64_t
1715
  uint64_t count;
1 by brian
clean slate
1716
  struct timeval start_time, end_time;
142.1.2 by Patrick
All DBUG_x removed from client/
1717
1 by brian
clean slate
1718
1719
  gettimeofday(&start_time, NULL);
1720
1721
  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1722
1723
  if (verbose >= 2)
1724
    printf("Loading Pre-data\n");
1725
1726
  if (run_query(mysql, query, len))
1727
  {
1728
    fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1729
            mysql_error(mysql));
1730
    exit(1);
1731
  }
1732
  else
1733
  {
1734
    sptr->create_count++;
1735
  }
1736
1737
  if (opt_only_print)
1738
  {
1739
    printf("use %s;\n", db);
1740
  }
1741
  else
1742
  {
1743
    if (verbose >= 3)
1744
      printf("%s;\n", query);
1745
1746
    if (mysql_select_db(mysql,  db))
1747
    {
1748
      fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1749
              mysql_error(mysql));
1750
      exit(1);
1751
    }
1752
    sptr->create_count++;
1753
  }
1754
1755
  if (engine_stmt)
1756
  {
1757
    len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1758
                  engine_stmt->string);
1759
    if (run_query(mysql, query, len))
1760
    {
1761
      fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
1762
              mysql_error(mysql));
1763
      exit(1);
1764
    }
1765
    sptr->create_count++;
1766
  }
1767
1768
  count= 0;
1769
  after_create= stmt;
1770
1771
limit_not_met:
1772
  for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1773
  {
1774
    if (auto_generate_sql && ( auto_generate_sql_number == count))
1775
      break;
1776
1777
    if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1778
    {
1779
      char buffer[HUGE_STRING_LENGTH];
1780
1781
      snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string, 
1782
               engine_stmt->option);
1783
      if (run_query(mysql, buffer, strlen(buffer)))
1784
      {
1785
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1786
                my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1787
        if (!opt_ignore_sql_errors)
1788
          exit(1);
1789
      }
1790
      sptr->create_count++;
1791
    }
1792
    else
1793
    {
1794
      if (run_query(mysql, ptr->string, ptr->length))
1795
      {
1796
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1797
                my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1798
        if (!opt_ignore_sql_errors)
1799
          exit(1);
1800
      }
1801
      sptr->create_count++;
1802
    }
1803
  }
1804
1805
  if (auto_generate_sql && (auto_generate_sql_number > count ))
1806
  {
1807
    /* Special case for auto create, we don't want to create tables twice */
1808
    after_create= stmt->next;
1809
    goto limit_not_met;
1810
  }
1811
1812
  gettimeofday(&end_time, NULL);
1813
1814
  sptr->create_timing= timedif(end_time, start_time);
1815
142.1.2 by Patrick
All DBUG_x removed from client/
1816
  return(0);
1 by brian
clean slate
1817
}
1818
1819
static int
1820
drop_schema(MYSQL *mysql, const char *db)
1821
{
1822
  char query[HUGE_STRING_LENGTH];
1823
  int len;
142.1.2 by Patrick
All DBUG_x removed from client/
1824
1 by brian
clean slate
1825
  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1826
1827
  if (run_query(mysql, query, len))
1828
  {
1829
    fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1830
            my_progname, db, mysql_error(mysql));
1831
    exit(1);
1832
  }
1833
1834
1835
142.1.2 by Patrick
All DBUG_x removed from client/
1836
  return(0);
1 by brian
clean slate
1837
}
1838
1839
static int
1840
run_statements(MYSQL *mysql, statement *stmt) 
1841
{
1842
  statement *ptr;
1843
  MYSQL_RES *result;
142.1.2 by Patrick
All DBUG_x removed from client/
1844
1 by brian
clean slate
1845
1846
  for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1847
  {
1848
    if (run_query(mysql, ptr->string, ptr->length))
1849
    {
1850
      fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1851
              my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1852
      exit(1);
1853
    }
1854
    if (!opt_only_print)
1855
    {
1856
      if (mysql_field_count(mysql))
1857
      {
1858
        result= mysql_store_result(mysql);
1859
        mysql_free_result(result);
1860
      }
1861
    }
1862
  }
1863
142.1.2 by Patrick
All DBUG_x removed from client/
1864
  return(0);
1 by brian
clean slate
1865
}
1866
1867
static int
151 by Brian Aker
Ulonglong to uint64_t
1868
run_scheduler(stats *sptr, statement **stmts, uint concur, uint64_t limit)
1 by brian
clean slate
1869
{
1870
  uint x;
1871
  uint y;
1872
  unsigned int real_concurrency;
1873
  struct timeval start_time, end_time;
1874
  option_string *sql_type;
1875
  thread_context *con;
1876
  pthread_t mainthread;            /* Thread descriptor */
1877
  pthread_attr_t attr;          /* Thread attributes */
142.1.2 by Patrick
All DBUG_x removed from client/
1878
1 by brian
clean slate
1879
1880
  pthread_attr_init(&attr);
1881
  pthread_attr_setdetachstate(&attr,
1882
		  PTHREAD_CREATE_DETACHED);
1883
1884
  pthread_mutex_lock(&counter_mutex);
1885
  thread_counter= 0;
1886
1887
  pthread_mutex_lock(&sleeper_mutex);
1888
  master_wakeup= 1;
1889
  pthread_mutex_unlock(&sleeper_mutex);
1890
1891
  real_concurrency= 0;
1892
1893
  for (y= 0, sql_type= query_options; 
1894
       y < query_statements_count; 
1895
       y++, sql_type= sql_type->next)
1896
  {
1897
    unsigned int options_loop= 1;
1898
1899
    if (sql_type->option)
1900
    {
1901
      options_loop= strtol(sql_type->option, 
1902
                           (char **)NULL, 10);
1903
      options_loop= options_loop ? options_loop : 1;
1904
    }
1905
1906
    while (options_loop--)
1907
      for (x= 0; x < concur; x++)
1908
      {
1909
        con= (thread_context *)my_malloc(sizeof(thread_context), MYF(0));
1910
        con->stmt= stmts[y];
1911
        con->limit= limit;
1912
1913
        real_concurrency++;
1914
        /* now you create the thread */
1915
        if (pthread_create(&mainthread, &attr, run_task, 
1916
                           (void *)con) != 0)
1917
        {
1918
          fprintf(stderr,"%s: Could not create thread\n", my_progname);
1919
          exit(1);
1920
        }
1921
        thread_counter++;
1922
      }
1923
  }
1924
1925
  /* 
1926
    The timer_thread belongs to all threads so it too obeys the wakeup 
1927
    call that run tasks obey.
1928
  */
1929
  if (opt_timer_length)
1930
  {
1931
    pthread_mutex_lock(&timer_alarm_mutex);
163 by Brian Aker
Merge Monty's code.
1932
    timer_alarm= true;
1 by brian
clean slate
1933
    pthread_mutex_unlock(&timer_alarm_mutex);
1934
1935
    if (pthread_create(&mainthread, &attr, timer_thread, 
1936
                       (void *)&opt_timer_length) != 0)
1937
    {
1938
      fprintf(stderr,"%s: Could not create timer thread\n", my_progname);
1939
      exit(1);
1940
    }
1941
  }
1942
1943
  pthread_mutex_unlock(&counter_mutex);
1944
  pthread_attr_destroy(&attr);
1945
1946
  pthread_mutex_lock(&sleeper_mutex);
1947
  master_wakeup= 0;
1948
  pthread_mutex_unlock(&sleeper_mutex);
1949
  pthread_cond_broadcast(&sleep_threshhold);
1950
1951
  gettimeofday(&start_time, NULL);
1952
1953
  /*
1954
    We loop until we know that all children have cleaned up.
1955
  */
1956
  pthread_mutex_lock(&counter_mutex);
1957
  while (thread_counter)
1958
  {
1959
    struct timespec abstime;
1960
1961
    set_timespec(abstime, 3);
1962
    pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1963
  }
1964
  pthread_mutex_unlock(&counter_mutex);
1965
1966
  gettimeofday(&end_time, NULL);
1967
1968
1969
  sptr->timing= timedif(end_time, start_time);
1970
  sptr->users= concur;
1971
  sptr->real_users= real_concurrency;
1972
  sptr->rows= limit;
1973
142.1.2 by Patrick
All DBUG_x removed from client/
1974
  return(0);
1 by brian
clean slate
1975
}
1976
1977
1978
pthread_handler_t timer_thread(void *p)
1979
{
1980
  uint *timer_length= (uint *)p;
1981
  struct timespec abstime;
1982
142.1.2 by Patrick
All DBUG_x removed from client/
1983
1 by brian
clean slate
1984
1985
  if (mysql_thread_init())
1986
  {
1987
    fprintf(stderr,"%s: mysql_thread_init() failed.\n",
1988
            my_progname);
1989
    exit(1);
1990
  }
1991
1992
  /* 
1993
    We lock around the initial call in case were we in a loop. This 
1994
    also keeps the value properly syncronized across call threads.
1995
  */
1996
  pthread_mutex_lock(&sleeper_mutex);
1997
  while (master_wakeup)
1998
  {
1999
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2000
  }
2001
  pthread_mutex_unlock(&sleeper_mutex);
2002
2003
  set_timespec(abstime, *timer_length);
2004
2005
  pthread_mutex_lock(&timer_alarm_mutex);
2006
  pthread_cond_timedwait(&timer_alarm_threshold, &timer_alarm_mutex, &abstime);
2007
  pthread_mutex_unlock(&timer_alarm_mutex);
2008
2009
  pthread_mutex_lock(&timer_alarm_mutex);
163 by Brian Aker
Merge Monty's code.
2010
  timer_alarm= false;
1 by brian
clean slate
2011
  pthread_mutex_unlock(&timer_alarm_mutex);
2012
2013
  mysql_thread_end();
142.1.2 by Patrick
All DBUG_x removed from client/
2014
  return(0);
1 by brian
clean slate
2015
}
2016
2017
pthread_handler_t run_task(void *p)
2018
{
151 by Brian Aker
Ulonglong to uint64_t
2019
  uint64_t counter= 0, queries;
2020
  uint64_t detach_counter;
1 by brian
clean slate
2021
  unsigned int commit_counter;
2022
  MYSQL mysql;
2023
  MYSQL_RES *result;
2024
  MYSQL_ROW row;
2025
  statement *ptr;
2026
  thread_context *con= (thread_context *)p;
2027
2028
  if (mysql_thread_init())
2029
  {
2030
    fprintf(stderr,"%s: mysql_thread_init() failed.\n",
2031
            my_progname);
2032
    exit(1);
2033
  }
2034
2035
  pthread_mutex_lock(&sleeper_mutex);
2036
  while (master_wakeup)
2037
  {
2038
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2039
  }
2040
  pthread_mutex_unlock(&sleeper_mutex);
2041
163 by Brian Aker
Merge Monty's code.
2042
  slap_connect(&mysql, true);
1 by brian
clean slate
2043
2044
  if (verbose >= 3)
2045
    printf("connected!\n");
2046
  queries= 0;
2047
2048
  commit_counter= 0;
2049
  if (commit_rate)
2050
    run_query(&mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
2051
2052
limit_not_met:
2053
    for (ptr= con->stmt, detach_counter= 0; 
2054
         ptr && ptr->length; 
2055
         ptr= ptr->next, detach_counter++)
2056
    {
2057
      if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
2058
      {
2059
        slap_close(&mysql);
163 by Brian Aker
Merge Monty's code.
2060
        slap_connect(&mysql, true);
1 by brian
clean slate
2061
      }
2062
2063
      /* 
2064
        We have to execute differently based on query type. This should become a function.
2065
      */
2066
      if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
2067
          (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
2068
      {
2069
        int length;
2070
        unsigned int key_val;
2071
        char *key;
2072
        char buffer[HUGE_STRING_LENGTH];
2073
2074
        /* 
2075
          This should only happen if some sort of new engine was
2076
          implemented that didn't properly handle UPDATEs.
2077
2078
          Just in case someone runs this under an experimental engine we don't
2079
          want a crash so the if() is placed here.
2080
        */
142.1.2 by Patrick
All DBUG_x removed from client/
2081
        assert(primary_keys_number_of);
1 by brian
clean slate
2082
        if (primary_keys_number_of)
2083
        {
2084
          key_val= (unsigned int)(random() % primary_keys_number_of);
2085
          key= primary_keys[key_val];
2086
142.1.2 by Patrick
All DBUG_x removed from client/
2087
          assert(key);
1 by brian
clean slate
2088
2089
          length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", 
2090
                           (int)ptr->length, ptr->string, key);
2091
2092
          if (run_query(&mysql, buffer, length))
2093
          {
2094
            fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2095
                    my_progname, (uint)length, buffer, mysql_error(&mysql));
2096
            exit(1);
2097
          }
2098
        }
2099
      }
2100
      else
2101
      {
2102
        if (run_query(&mysql, ptr->string, ptr->length))
2103
        {
2104
          fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2105
                  my_progname, (uint)ptr->length, ptr->string, mysql_error(&mysql));
2106
          exit(1);
2107
        }
2108
      }
2109
2110
      if (!opt_only_print)
2111
      {
2112
        do
2113
        {
2114
          if (mysql_field_count(&mysql))
2115
          {
2116
            result= mysql_store_result(&mysql);
2117
            while ((row = mysql_fetch_row(result)))
2118
              counter++;
2119
            mysql_free_result(result);
2120
          }
2121
        } while(mysql_next_result(&mysql) == 0);
2122
      }
2123
      queries++;
2124
2125
      if (commit_rate && (++commit_counter == commit_rate))
2126
      {
2127
        commit_counter= 0;
2128
        run_query(&mysql, "COMMIT", strlen("COMMIT"));
2129
      }
2130
2131
      /* If the timer is set, and the alarm is not active then end */
163 by Brian Aker
Merge Monty's code.
2132
      if (opt_timer_length && timer_alarm == false)
1 by brian
clean slate
2133
        goto end;
2134
2135
      /* If limit has been reached, and we are not in a timer_alarm just end */
163 by Brian Aker
Merge Monty's code.
2136
      if (con->limit && queries == con->limit && timer_alarm == false)
1 by brian
clean slate
2137
        goto end;
2138
    }
2139
163 by Brian Aker
Merge Monty's code.
2140
    if (opt_timer_length && timer_alarm == true)
1 by brian
clean slate
2141
      goto limit_not_met;
2142
2143
    if (con->limit && queries < con->limit)
2144
      goto limit_not_met;
2145
2146
2147
end:
2148
  if (commit_rate)
2149
    run_query(&mysql, "COMMIT", strlen("COMMIT"));
2150
2151
  slap_close(&mysql);
2152
2153
  pthread_mutex_lock(&counter_mutex);
2154
  thread_counter--;
2155
  pthread_cond_signal(&count_threshhold);
2156
  pthread_mutex_unlock(&counter_mutex);
2157
2158
  my_free(con, MYF(0));
2159
2160
  mysql_thread_end();
142.1.2 by Patrick
All DBUG_x removed from client/
2161
  return(0);
1 by brian
clean slate
2162
}
2163
2164
/*
2165
  Parse records from comma seperated string. : is a reserved character and is used for options
2166
  on variables.
2167
*/
2168
uint
2169
parse_option(const char *origin, option_string **stmt, char delm)
2170
{
2171
  char *string;
2172
  char *begin_ptr;
2173
  char *end_ptr;
2174
  option_string **sptr= stmt;
2175
  option_string *tmp;
2176
  uint length= strlen(origin);
2177
  uint count= 0; /* We know that there is always one */
2178
2179
  end_ptr= (char *)origin + length;
2180
2181
  tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
2182
                                         MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2183
2184
  for (begin_ptr= (char *)origin;
2185
       begin_ptr != end_ptr;
2186
       tmp= tmp->next)
2187
  {
2188
    char buffer[HUGE_STRING_LENGTH];
2189
    char *buffer_ptr;
2190
2191
    bzero(buffer, HUGE_STRING_LENGTH);
2192
2193
    string= strchr(begin_ptr, delm); 
2194
2195
    if (string)
2196
    {
2197
      memcpy(buffer, begin_ptr, string - begin_ptr);
2198
      begin_ptr= string+1;
2199
    }
2200
    else
2201
    {
2202
      size_t length= strlen(begin_ptr);
2203
      memcpy(buffer, begin_ptr, length);
2204
      begin_ptr= end_ptr;
2205
    }
2206
2207
    if ((buffer_ptr= strchr(buffer, ':')))
2208
    {
2209
      /* Set a null so that we can get strlen() correct later on */
2210
      buffer_ptr[0]= 0;
2211
      buffer_ptr++;
2212
2213
      /* Move past the : and the first string */
2214
      tmp->option_length= strlen(buffer_ptr);
2215
      tmp->option= my_strndup(buffer_ptr, (uint)tmp->option_length,
2216
                              MYF(MY_FAE));
2217
    }
2218
2219
    tmp->string= my_strndup(buffer, strlen(buffer), MYF(MY_FAE));
2220
    tmp->length= strlen(buffer);
2221
2222
    if (isspace(*begin_ptr))
2223
      begin_ptr++;
2224
2225
    count++;
2226
2227
    if (begin_ptr != end_ptr)
2228
      tmp->next= (option_string *)my_malloc(sizeof(option_string),
2229
                                            MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2230
  }
2231
2232
  return count;
2233
}
2234
2235
2236
/*
2237
  Raw parsing interface. If you want the slap specific parser look at
2238
  parse_option.
2239
*/
2240
uint
2241
parse_delimiter(const char *script, statement **stmt, char delm)
2242
{
2243
  char *retstr;
2244
  char *ptr= (char *)script;
2245
  statement **sptr= stmt;
2246
  statement *tmp;
2247
  uint length= strlen(script);
2248
  uint count= 0; /* We know that there is always one */
2249
2250
  for (tmp= *sptr= (statement *)my_malloc(sizeof(statement),
2251
                                          MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2252
       (retstr= strchr(ptr, delm)); 
2253
       tmp->next=  (statement *)my_malloc(sizeof(statement),
2254
                                          MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2255
       tmp= tmp->next)
2256
  {
2257
    count++;
2258
    tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE));
2259
    tmp->length= (size_t)(retstr - ptr);
2260
    ptr+= retstr - ptr + 1;
2261
    if (isspace(*ptr))
2262
      ptr++;
2263
  }
2264
2265
  if (ptr != script+length)
2266
  {
2267
    tmp->string= my_strndup(ptr, (uint)((script + length) - ptr), 
2268
                                       MYF(MY_FAE));
2269
    tmp->length= (size_t)((script + length) - ptr);
2270
    count++;
2271
  }
2272
2273
  return count;
2274
}
2275
2276
2277
/*
2278
  Parse comma is different from parse_delimeter in that it parses
2279
  number ranges from a comma seperated string.
2280
  In restrospect, this is a lousy name from this function.
2281
*/
2282
uint
2283
parse_comma(const char *string, uint **range)
2284
{
2285
  uint count= 1,x; /* We know that there is always one */
2286
  char *retstr;
2287
  char *ptr= (char *)string;
2288
  uint *nptr;
2289
2290
  for (;*ptr; ptr++)
2291
    if (*ptr == ',') count++;
2292
  
2293
  /* One extra spot for the NULL */
2294
  nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1), 
2295
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2296
2297
  ptr= (char *)string;
2298
  x= 0;
2299
  while ((retstr= strchr(ptr,',')))
2300
  {
2301
    nptr[x++]= atoi(ptr);
2302
    ptr+= retstr - ptr + 1;
2303
  }
2304
  nptr[x++]= atoi(ptr);
2305
2306
  return count;
2307
}
2308
2309
void
2310
print_conclusions(conclusions *con)
2311
{
2312
  printf("Benchmark\n");
2313
  if (con->engine)
2314
      printf("\tRunning for engine %s\n", con->engine);
2315
  if (opt_label || opt_auto_generate_sql_type)
2316
  {
2317
    const char *ptr= opt_auto_generate_sql_type ? opt_auto_generate_sql_type : "query";
2318
    printf("\tLoad: %s\n", opt_label ? opt_label : ptr);
2319
  }
2320
  printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
2321
         con->create_avg_timing / 1000, con->create_avg_timing % 1000);
2322
  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2323
         con->avg_timing / 1000, con->avg_timing % 1000);
2324
  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2325
         con->min_timing / 1000, con->min_timing % 1000);
2326
  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2327
         con->max_timing / 1000, con->max_timing % 1000);
2328
  printf("\tTotal time for tests: %ld.%03ld seconds\n", 
2329
         con->sum_of_time / 1000, con->sum_of_time % 1000);
2330
  printf("\tStandard Deviation: %ld.%03ld\n", con->std_dev / 1000, con->std_dev % 1000);
2331
  printf("\tNumber of queries in create queries: %llu\n", con->create_count);
2332
  printf("\tNumber of clients running queries: %u/%u\n", 
2333
         con->users, con->real_users);
2334
  printf("\tNumber of times test was run: %u\n", iterations);
2335
  printf("\tAverage number of queries per client: %llu\n", con->avg_rows); 
2336
  printf("\n");
2337
}
2338
2339
void
2340
print_conclusions_csv(conclusions *con)
2341
{
2342
  unsigned int x;
2343
  char buffer[HUGE_STRING_LENGTH];
2344
  char label_buffer[HUGE_STRING_LENGTH];
2345
  size_t string_len;
2346
2347
  bzero(label_buffer, HUGE_STRING_LENGTH);
2348
2349
  if (opt_label)
2350
  {
2351
    string_len= strlen(opt_label);
2352
2353
    for (x= 0; x < string_len; x++)
2354
    {
2355
      if (opt_label[x] == ',')
2356
        label_buffer[x]= '-';
2357
      else
2358
        label_buffer[x]= opt_label[x] ;
2359
    }
2360
  } 
2361
  else if (opt_auto_generate_sql_type)
2362
  {
2363
    string_len= strlen(opt_auto_generate_sql_type);
2364
2365
    for (x= 0; x < string_len; x++)
2366
    {
2367
      if (opt_auto_generate_sql_type[x] == ',')
2368
        label_buffer[x]= '-';
2369
      else
2370
        label_buffer[x]= opt_auto_generate_sql_type[x] ;
2371
    }
2372
  }
2373
  else
2374
    snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2375
2376
  snprintf(buffer, HUGE_STRING_LENGTH, 
2377
           "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%u,%u,%u,%llu\n",
2378
           con->engine ? con->engine : "", /* Storage engine we ran against */
2379
           label_buffer, /* Load type */
2380
           con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2381
           con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2382
           con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2383
           con->sum_of_time / 1000, con->sum_of_time % 1000, /* Total time */
2384
           con->std_dev / 1000, con->std_dev % 1000, /* Standard Deviation */
2385
           iterations, /* Iterations */
2386
           con->users, /* Children used max_timing */
2387
           con->real_users, /* Children used max_timing */
2388
           con->avg_rows  /* Queries run */
2389
          );
2390
  my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2391
}
2392
2393
void
2394
generate_stats(conclusions *con, option_string *eng, stats *sptr)
2395
{
2396
  stats *ptr;
2397
  unsigned int x;
2398
2399
  con->min_timing= sptr->timing; 
2400
  con->max_timing= sptr->timing;
2401
  con->min_rows= sptr->rows;
2402
  con->max_rows= sptr->rows;
2403
  
2404
  /* At the moment we assume uniform */
2405
  con->users= sptr->users;
2406
  con->real_users= sptr->real_users;
2407
  con->avg_rows= sptr->rows;
2408
  
2409
  /* With no next, we know it is the last element that was malloced */
2410
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2411
  {
2412
    con->avg_timing+= ptr->timing;
2413
2414
    if (ptr->timing > con->max_timing)
2415
      con->max_timing= ptr->timing;
2416
    if (ptr->timing < con->min_timing)
2417
      con->min_timing= ptr->timing;
2418
  }
2419
  con->sum_of_time= con->avg_timing;
2420
  con->avg_timing= con->avg_timing/iterations;
2421
2422
  if (eng && eng->string)
2423
    con->engine= eng->string;
2424
  else
2425
    con->engine= NULL;
2426
2427
  standard_deviation(con, sptr);
2428
2429
  /* Now we do the create time operations */
2430
  con->create_min_timing= sptr->create_timing; 
2431
  con->create_max_timing= sptr->create_timing;
2432
  
2433
  /* At the moment we assume uniform */
2434
  con->create_count= sptr->create_count;
2435
  
2436
  /* With no next, we know it is the last element that was malloced */
2437
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2438
  {
2439
    con->create_avg_timing+= ptr->create_timing;
2440
2441
    if (ptr->create_timing > con->create_max_timing)
2442
      con->create_max_timing= ptr->create_timing;
2443
    if (ptr->create_timing < con->create_min_timing)
2444
      con->create_min_timing= ptr->create_timing;
2445
  }
2446
  con->create_avg_timing= con->create_avg_timing/iterations;
2447
}
2448
2449
void
2450
option_cleanup(option_string *stmt)
2451
{
2452
  option_string *ptr, *nptr;
2453
  if (!stmt)
2454
    return;
2455
2456
  for (ptr= stmt; ptr; ptr= nptr)
2457
  {
2458
    nptr= ptr->next;
2459
    if (ptr->string)
2460
      my_free(ptr->string, MYF(0)); 
2461
    if (ptr->option)
2462
      my_free(ptr->option, MYF(0)); 
2463
    my_free(ptr, MYF(0));
2464
  }
2465
}
2466
2467
void
2468
statement_cleanup(statement *stmt)
2469
{
2470
  statement *ptr, *nptr;
2471
  if (!stmt)
2472
    return;
2473
2474
  for (ptr= stmt; ptr; ptr= nptr)
2475
  {
2476
    nptr= ptr->next;
2477
    if (ptr->string)
2478
      my_free(ptr->string, MYF(0)); 
2479
    my_free(ptr, MYF(0));
2480
  }
2481
}
2482
2483
void 
2484
slap_close(MYSQL *mysql)
2485
{
2486
  if (opt_only_print) 
2487
    return;
2488
2489
  mysql_close(mysql);
2490
}
2491
2492
void 
143 by Brian Aker
Bool cleanup.
2493
slap_connect(MYSQL *mysql, bool connect_to_schema)
1 by brian
clean slate
2494
{
2495
  /* Connect to server */
2496
  static ulong connection_retry_sleep= 100000; /* Microseconds */
2497
  int x, connect_error= 1;
2498
2499
  if (opt_only_print) 
2500
    return;
2501
2502
  if (opt_delayed_start)
2503
    my_sleep(random()%opt_delayed_start);
2504
2505
  mysql_init(mysql);
2506
2507
  if (opt_compress)
2508
    mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
2509
  /* We always do opt_protocol to TCP/IP */
2510
  mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
2511
  mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
2512
2513
  for (x= 0; x < 10; x++)
2514
  {
2515
2516
2517
    if (mysql_real_connect(mysql, host, user, opt_password,
2518
                           connect_to_schema ? create_schema_string : NULL,
2519
                           opt_mysql_port,
2520
                           opt_mysql_unix_port,
2521
                           connect_flags))
2522
    {
2523
      /* Connect suceeded */
2524
      connect_error= 0;
2525
      break;
2526
    }
2527
    my_sleep(connection_retry_sleep);
2528
  }
2529
  if (connect_error)
2530
  {
2531
    fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2532
            my_progname, mysql_errno(mysql), mysql_error(mysql));
2533
    exit(1);
2534
  }
2535
2536
  return;
2537
}
2538
2539
void 
2540
standard_deviation (conclusions *con, stats *sptr)
2541
{
2542
  unsigned int x;
2543
  long int sum_of_squares;
2544
  double catch;
2545
  stats *ptr;
2546
2547
  if (iterations == 1 || iterations == 0)
2548
  {
2549
    con->std_dev= 0;
2550
    return;
2551
  }
2552
2553
  for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2554
  {
2555
    long int deviation;
2556
2557
    deviation= ptr->timing - con->avg_timing;
2558
    sum_of_squares+= deviation*deviation;
2559
  }
2560
2561
  catch= sqrt((double)(sum_of_squares/(iterations -1)));
2562
  con->std_dev= (long int)catch;
2563
}