~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
  {"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)
681
    (char**) &opt_silent, (char**) &opt_silent, 0, GET_BOOL,  NO_ARG,
1 by brian
clean slate
682
    0, 0, 0, 0, 0, 0},
683
  {"socket", 'S', "Socket file to use for connection.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
684
    (char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR,
1 by brian
clean slate
685
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
686
  {"timer-length", OPT_SLAP_TIMER_LENGTH, 
687
    "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)
688
    (char**) &opt_timer_length, (char**) &opt_timer_length, 0, GET_UINT, 
1 by brian
clean slate
689
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
690
#ifndef DONT_ALLOW_USER_CHANGE
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
691
  {"user", 'u', "User for login if not current user.", (char**) &user,
692
    (char**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
693
#endif
694
  {"verbose", 'v',
695
    "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)
696
      "verbose output.", (char**) &verbose, (char**) &verbose, 0, 
1 by brian
clean slate
697
      GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
698
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
699
    NO_ARG, 0, 0, 0, 0, 0, 0},
700
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
701
};
702
703
704
#include <help_start.h>
705
706
static void print_version(void)
707
{
708
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
709
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
710
}
711
712
713
static void usage(void)
714
{
715
  print_version();
716
  puts("Copyright (C) 2005 MySQL AB");
717
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
718
       \nand you are welcome to modify and redistribute it under the GPL \
719
       license\n");
720
  puts("Run a query multiple times against the server\n");
721
  printf("Usage: %s [OPTIONS]\n",my_progname);
722
  print_defaults("my",load_default_groups);
723
  my_print_help(my_long_options);
724
}
725
726
#include <help_end.h>
727
143 by Brian Aker
Bool cleanup.
728
static bool
1 by brian
clean slate
729
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
730
               char *argument)
731
{
142.1.2 by Patrick
All DBUG_x removed from client/
732
1 by brian
clean slate
733
  switch(optid) {
734
  case 'v':
735
    verbose++;
736
    break;
737
  case 'p':
738
    if (argument)
739
    {
740
      char *start= argument;
741
      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
742
      opt_password= my_strdup(argument,MYF(MY_FAE));
743
      while (*argument) *argument++= 'x';		/* Destroy argument */
744
      if (*start)
745
        start[1]= 0;				/* Cut length of argument */
746
      tty_password= 0;
747
    }
748
    else
749
      tty_password= 1;
750
    break;
751
  case 'V':
752
    print_version();
753
    exit(0);
754
    break;
755
  case '?':
756
  case 'I':					/* Info */
757
    usage();
758
    exit(0);
759
  }
142.1.2 by Patrick
All DBUG_x removed from client/
760
  return(0);
1 by brian
clean slate
761
}
762
763
764
uint
765
get_random_string(char *buf, size_t size)
766
{
767
  char *buf_ptr= buf;
768
  size_t x;
142.1.2 by Patrick
All DBUG_x removed from client/
769
1 by brian
clean slate
770
  for (x= size; x > 0; x--)
771
    *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
142.1.2 by Patrick
All DBUG_x removed from client/
772
  return(buf_ptr - buf);
1 by brian
clean slate
773
}
774
775
776
/*
777
  build_table_string
778
779
  This function builds a create table query if the user opts to not supply
780
  a file or string containing a create table statement
781
*/
782
static statement *
783
build_table_string(void)
784
{
785
  char       buf[HUGE_STRING_LENGTH];
786
  unsigned int        col_count;
787
  statement *ptr;
788
  DYNAMIC_STRING table_string;
789
790
  init_dynamic_string(&table_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
791
792
  dynstr_append(&table_string, "CREATE TABLE `t1` (");
793
794
  if (auto_generate_sql_autoincrement)
795
  {
796
    dynstr_append(&table_string, "id serial");
797
798
    if (num_int_cols || num_char_cols)
799
      dynstr_append(&table_string, ",");
800
  }
801
802
  if (auto_generate_sql_guid_primary)
803
  {
804
    dynstr_append(&table_string, "id varchar(128) primary key");
805
806
    if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
807
      dynstr_append(&table_string, ",");
808
  }
809
810
  if (auto_generate_sql_secondary_indexes)
811
  {
812
    unsigned int count;
813
814
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
815
    {
816
      if (count) /* Except for the first pass we add a comma */
817
        dynstr_append(&table_string, ",");
818
819
      if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count) 
820
          > HUGE_STRING_LENGTH)
821
      {
822
        fprintf(stderr, "Memory Allocation error in create table\n");
823
        exit(1);
824
      }
825
      dynstr_append(&table_string, buf);
826
    }
827
828
    if (num_int_cols || num_char_cols)
829
      dynstr_append(&table_string, ",");
830
  }
831
832
  if (num_int_cols)
833
    for (col_count= 1; col_count <= num_int_cols; col_count++)
834
    {
835
      if (num_int_cols_index)
836
      {
837
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)", 
838
                     col_count, col_count) > HUGE_STRING_LENGTH)
839
        {
840
          fprintf(stderr, "Memory Allocation error in create table\n");
841
          exit(1);
842
        }
843
      }
844
      else
845
      {
846
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count) 
847
            > HUGE_STRING_LENGTH)
848
        {
849
          fprintf(stderr, "Memory Allocation error in create table\n");
850
          exit(1);
851
        }
852
      }
853
      dynstr_append(&table_string, buf);
854
855
      if (col_count < num_int_cols || num_char_cols > 0)
856
        dynstr_append(&table_string, ",");
857
    }
858
859
  if (num_char_cols)
860
    for (col_count= 1; col_count <= num_char_cols; col_count++)
861
    {
862
      if (num_char_cols_index)
863
      {
864
        if (snprintf(buf, HUGE_STRING_LENGTH, 
865
                     "charcol%d VARCHAR(128), INDEX(charcol%d) ", 
866
                     col_count, col_count) > HUGE_STRING_LENGTH)
867
        {
868
          fprintf(stderr, "Memory Allocation error in creating table\n");
869
          exit(1);
870
        }
871
      }
872
      else
873
      {
874
        if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)", 
875
                     col_count) > HUGE_STRING_LENGTH)
876
        {
877
          fprintf(stderr, "Memory Allocation error in creating table\n");
878
          exit(1);
879
        }
880
      }
881
      dynstr_append(&table_string, buf);
882
883
      if (col_count < num_char_cols || num_blob_cols > 0)
884
        dynstr_append(&table_string, ",");
885
    }
886
887
  if (num_blob_cols)
888
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
889
    {
890
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob", 
891
                   col_count) > HUGE_STRING_LENGTH)
892
      {
893
        fprintf(stderr, "Memory Allocation error in creating table\n");
894
        exit(1);
895
      }
896
      dynstr_append(&table_string, buf);
897
898
      if (col_count < num_blob_cols)
899
        dynstr_append(&table_string, ",");
900
    }
901
902
  dynstr_append(&table_string, ")");
903
  ptr= (statement *)my_malloc(sizeof(statement), 
904
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
905
  ptr->string = (char *)my_malloc(table_string.length+1,
906
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
907
  ptr->length= table_string.length+1;
908
  ptr->type= CREATE_TABLE_TYPE;
909
  strmov(ptr->string, table_string.str);
910
  dynstr_free(&table_string);
142.1.2 by Patrick
All DBUG_x removed from client/
911
  return(ptr);
1 by brian
clean slate
912
}
913
914
/*
915
  build_update_string()
916
917
  This function builds insert statements when the user opts to not supply
918
  an insert file or string containing insert data
919
*/
920
static statement *
921
build_update_string(void)
922
{
923
  char       buf[HUGE_STRING_LENGTH];
924
  unsigned int        col_count;
925
  statement *ptr;
926
  DYNAMIC_STRING update_string;
142.1.2 by Patrick
All DBUG_x removed from client/
927
1 by brian
clean slate
928
929
  init_dynamic_string(&update_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
930
931
  dynstr_append(&update_string, "UPDATE t1 SET ");
932
933
  if (num_int_cols)
934
    for (col_count= 1; col_count <= num_int_cols; col_count++)
935
    {
936
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count, 
937
                   random()) > HUGE_STRING_LENGTH)
938
      {
939
        fprintf(stderr, "Memory Allocation error in creating update\n");
940
        exit(1);
941
      }
942
      dynstr_append(&update_string, buf);
943
944
      if (col_count < num_int_cols || num_char_cols > 0)
945
        dynstr_append_mem(&update_string, ",", 1);
946
    }
947
948
  if (num_char_cols)
949
    for (col_count= 1; col_count <= num_char_cols; col_count++)
950
    {
951
      char rand_buffer[RAND_STRING_SIZE];
952
      int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
953
954
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count, 
955
                   buf_len, rand_buffer) 
956
          > HUGE_STRING_LENGTH)
957
      {
958
        fprintf(stderr, "Memory Allocation error in creating update\n");
959
        exit(1);
960
      }
961
      dynstr_append(&update_string, buf);
962
963
      if (col_count < num_char_cols)
964
        dynstr_append_mem(&update_string, ",", 1);
965
    }
966
967
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
968
    dynstr_append(&update_string, " WHERE id = ");
969
970
971
  ptr= (statement *)my_malloc(sizeof(statement), 
972
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
973
974
  ptr->string= (char *)my_malloc(update_string.length + 1,
975
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
976
  ptr->length= update_string.length+1;
977
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
978
    ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
979
  else
980
    ptr->type= UPDATE_TYPE;
981
  strmov(ptr->string, update_string.str);
982
  dynstr_free(&update_string);
142.1.2 by Patrick
All DBUG_x removed from client/
983
  return(ptr);
1 by brian
clean slate
984
}
985
986
987
/*
988
  build_insert_string()
989
990
  This function builds insert statements when the user opts to not supply
991
  an insert file or string containing insert data
992
*/
993
static statement *
994
build_insert_string(void)
995
{
996
  char       buf[HUGE_STRING_LENGTH];
997
  unsigned int        col_count;
998
  statement *ptr;
999
  DYNAMIC_STRING insert_string;
142.1.2 by Patrick
All DBUG_x removed from client/
1000
1 by brian
clean slate
1001
1002
  init_dynamic_string(&insert_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
1003
1004
  dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
1005
1006
  if (auto_generate_sql_autoincrement)
1007
  {
1008
    dynstr_append(&insert_string, "NULL");
1009
1010
    if (num_int_cols || num_char_cols)
1011
      dynstr_append(&insert_string, ",");
1012
  }
1013
1014
  if (auto_generate_sql_guid_primary)
1015
  {
1016
    dynstr_append(&insert_string, "uuid()");
1017
1018
    if (num_int_cols || num_char_cols)
1019
      dynstr_append(&insert_string, ",");
1020
  }
1021
1022
  if (auto_generate_sql_secondary_indexes)
1023
  {
1024
    unsigned int count;
1025
1026
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1027
    {
1028
      if (count) /* Except for the first pass we add a comma */
1029
        dynstr_append(&insert_string, ",");
1030
1031
      dynstr_append(&insert_string, "uuid()");
1032
    }
1033
1034
    if (num_int_cols || num_char_cols)
1035
      dynstr_append(&insert_string, ",");
1036
  }
1037
1038
  if (num_int_cols)
1039
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1040
    {
1041
      if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1042
      {
1043
        fprintf(stderr, "Memory Allocation error in creating insert\n");
1044
        exit(1);
1045
      }
1046
      dynstr_append(&insert_string, buf);
1047
1048
      if (col_count < num_int_cols || num_char_cols > 0)
1049
        dynstr_append_mem(&insert_string, ",", 1);
1050
    }
1051
1052
  if (num_char_cols)
1053
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1054
    {
1055
      int buf_len= get_random_string(buf, RAND_STRING_SIZE);
1056
      dynstr_append_mem(&insert_string, "'", 1);
1057
      dynstr_append_mem(&insert_string, buf, buf_len);
1058
      dynstr_append_mem(&insert_string, "'", 1);
1059
1060
      if (col_count < num_char_cols || num_blob_cols > 0)
1061
        dynstr_append_mem(&insert_string, ",", 1);
1062
    }
1063
1064
  if (num_blob_cols)
1065
  {
1066
    char *blob_ptr;
1067
1068
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
1069
    {
1070
      blob_ptr= (char *)my_malloc(sizeof(char)*num_blob_cols_size,
1071
                             MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1072
      if (!blob_ptr)
1073
      {
1074
        fprintf(stderr, "Memory Allocation error in creating select\n");
1075
        exit(1);
1076
      }
1077
    }
1078
    else
1079
    {
1080
      blob_ptr= buf;
1081
    }
1082
1083
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1084
    {
1085
      unsigned int buf_len;
1086
      unsigned int size;
1087
      unsigned int difference= num_blob_cols_size - num_blob_cols_size_min;
1088
1089
      size= difference ? (num_blob_cols_size_min + (random() % difference)) : 
1090
                          num_blob_cols_size;
1091
1092
      buf_len= get_random_string(blob_ptr, size);
1093
1094
      dynstr_append_mem(&insert_string, "'", 1);
1095
      dynstr_append_mem(&insert_string, blob_ptr, buf_len);
1096
      dynstr_append_mem(&insert_string, "'", 1);
1097
1098
      if (col_count < num_blob_cols)
1099
        dynstr_append_mem(&insert_string, ",", 1);
1100
    }
1101
1102
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
1103
      my_free(blob_ptr, MYF(0));
1104
  }
1105
1106
  dynstr_append_mem(&insert_string, ")", 1);
1107
1108
  if (!(ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL|MY_FAE|MY_WME))))
1109
  {
1110
    fprintf(stderr, "Memory Allocation error in creating select\n");
1111
    exit(1);
1112
  }
1113
  if (!(ptr->string= (char *)my_malloc(insert_string.length + 1, MYF(MY_ZEROFILL|MY_FAE|MY_WME))))
1114
  {
1115
    fprintf(stderr, "Memory Allocation error in creating select\n");
1116
    exit(1);
1117
  }
1118
  ptr->length= insert_string.length+1;
1119
  ptr->type= INSERT_TYPE;
1120
  strmov(ptr->string, insert_string.str);
1121
  dynstr_free(&insert_string);
1122
142.1.2 by Patrick
All DBUG_x removed from client/
1123
  return(ptr);
1 by brian
clean slate
1124
}
1125
1126
1127
/*
1128
  build_select_string()
1129
1130
  This function builds a query if the user opts to not supply a query
1131
  statement or file containing a query statement
1132
*/
1133
static statement *
143 by Brian Aker
Bool cleanup.
1134
build_select_string(bool key)
1 by brian
clean slate
1135
{
1136
  char       buf[HUGE_STRING_LENGTH];
1137
  unsigned int        col_count;
1138
  statement *ptr;
1139
  static DYNAMIC_STRING query_string;
142.1.2 by Patrick
All DBUG_x removed from client/
1140
1 by brian
clean slate
1141
1142
  init_dynamic_string(&query_string, "", HUGE_STRING_LENGTH, HUGE_STRING_LENGTH);
1143
1144
  dynstr_append_mem(&query_string, "SELECT ", 7);
1145
  if (auto_generate_selected_columns_opt)
1146
  {
1147
    dynstr_append(&query_string, auto_generate_selected_columns_opt);
1148
  }
1149
  else
1150
  {
1151
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1152
    {
1153
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count) 
1154
          > HUGE_STRING_LENGTH)
1155
      {
1156
        fprintf(stderr, "Memory Allocation error in creating select\n");
1157
        exit(1);
1158
      }
1159
      dynstr_append(&query_string, buf);
1160
1161
      if (col_count < num_int_cols || num_char_cols > 0)
1162
        dynstr_append_mem(&query_string, ",", 1);
1163
1164
    }
1165
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1166
    {
1167
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1168
          > HUGE_STRING_LENGTH)
1169
      {
1170
        fprintf(stderr, "Memory Allocation error in creating select\n");
1171
        exit(1);
1172
      }
1173
      dynstr_append(&query_string, buf);
1174
1175
      if (col_count < num_char_cols || num_blob_cols > 0)
1176
        dynstr_append_mem(&query_string, ",", 1);
1177
1178
    }
1179
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1180
    {
1181
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
1182
          > HUGE_STRING_LENGTH)
1183
      {
1184
        fprintf(stderr, "Memory Allocation error in creating select\n");
1185
        exit(1);
1186
      }
1187
      dynstr_append(&query_string, buf);
1188
1189
      if (col_count < num_blob_cols)
1190
        dynstr_append_mem(&query_string, ",", 1);
1191
    }
1192
  }
1193
  dynstr_append(&query_string, " FROM t1");
1194
1195
  if ((key) && 
1196
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1197
    dynstr_append(&query_string, " WHERE id = ");
1198
1199
  ptr= (statement *)my_malloc(sizeof(statement),
1200
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1201
  ptr->string= (char *)my_malloc(query_string.length + 1,
1202
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1203
  ptr->length= query_string.length+1;
1204
  if ((key) && 
1205
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1206
    ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1207
  else
1208
    ptr->type= SELECT_TYPE;
1209
  strmov(ptr->string, query_string.str);
1210
  dynstr_free(&query_string);
142.1.2 by Patrick
All DBUG_x removed from client/
1211
  return(ptr);
1 by brian
clean slate
1212
}
1213
1214
static int
1215
get_options(int *argc,char ***argv)
1216
{
1217
  int ho_error;
1218
  char *tmp_string;
15 by brian
Fix for stat, NETWARE removal
1219
  struct stat sbuf;
1 by brian
clean slate
1220
  option_string *sql_type;
1221
  unsigned int sql_type_count= 0;
1222
142.1.2 by Patrick
All DBUG_x removed from client/
1223
1 by brian
clean slate
1224
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1225
    exit(ho_error);
1226
  if (debug_info_flag)
1227
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1228
  if (debug_check_flag)
1229
    my_end_arg= MY_CHECK_ERROR;
1230
1231
  if (!user)
1232
    user= (char *)"root";
1233
1234
  /* If something is created we clean it up, otherwise we leave schemas alone */
1235
  if (create_string || auto_generate_sql)
163 by Brian Aker
Merge Monty's code.
1236
    opt_preserve= false;
1 by brian
clean slate
1237
1238
  if (auto_generate_sql && (create_string || user_supplied_query))
1239
  {
1240
      fprintf(stderr,
1241
              "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1242
              my_progname);
1243
      exit(1);
1244
  }
1245
1246
  if (auto_generate_sql && auto_generate_sql_guid_primary && 
1247
      auto_generate_sql_autoincrement)
1248
  {
1249
      fprintf(stderr,
1250
              "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1251
              my_progname);
1252
      exit(1);
1253
  }
1254
1255
  if (auto_generate_sql && num_of_query && auto_actual_queries)
1256
  {
1257
      fprintf(stderr,
1258
              "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1259
              my_progname);
1260
      exit(1);
1261
  }
1262
1263
  parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1264
1265
  if (opt_csv_str)
1266
  {
163 by Brian Aker
Merge Monty's code.
1267
    opt_silent= true;
1 by brian
clean slate
1268
    
1269
    if (opt_csv_str[0] == '-')
1270
    {
1271
      csv_file= fileno(stdout);
1272
    }
1273
    else
1274
    {
1275
      if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1276
          == -1)
1277
      {
1278
        fprintf(stderr,"%s: Could not open csv file: %sn\n",
1279
                my_progname, opt_csv_str);
1280
        exit(1);
1281
      }
1282
    }
1283
  }
1284
1285
  if (opt_only_print)
163 by Brian Aker
Merge Monty's code.
1286
    opt_silent= true;
1 by brian
clean slate
1287
1288
  if (num_int_cols_opt)
1289
  {
1290
    option_string *str;
1291
    parse_option(num_int_cols_opt, &str, ',');
1292
    num_int_cols= atoi(str->string);
1293
    if (str->option)
1294
      num_int_cols_index= atoi(str->option);
1295
    option_cleanup(str);
1296
  }
1297
1298
  if (num_char_cols_opt)
1299
  {
1300
    option_string *str;
1301
    parse_option(num_char_cols_opt, &str, ',');
1302
    num_char_cols= atoi(str->string);
1303
    if (str->option)
1304
      num_char_cols_index= atoi(str->option);
1305
    else
1306
      num_char_cols_index= 0;
1307
    option_cleanup(str);
1308
  }
1309
1310
  if (num_blob_cols_opt)
1311
  {
1312
    option_string *str;
1313
    parse_option(num_blob_cols_opt, &str, ',');
1314
    num_blob_cols= atoi(str->string);
1315
    if (str->option)
1316
    {
1317
      char *sep_ptr;
1318
1319
      if ((sep_ptr= strchr(str->option, '/')))
1320
      {
1321
        num_blob_cols_size_min= atoi(str->option);
1322
        num_blob_cols_size= atoi(sep_ptr+1);
1323
      }
1324
      else
1325
      {
1326
        num_blob_cols_size_min= num_blob_cols_size= atoi(str->option);
1327
      }
1328
    }
1329
    else
1330
    {
1331
      num_blob_cols_size= DEFAULT_BLOB_SIZE;
1332
      num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
1333
    }
1334
    option_cleanup(str);
1335
  }
1336
1337
1338
  if (auto_generate_sql)
1339
  {
1340
    unsigned long long x= 0;
1341
    statement *ptr_statement;
1342
1343
    if (verbose >= 2)
1344
      printf("Building Create Statements for Auto\n");
1345
1346
    create_statements= build_table_string();
1347
    /* 
1348
      Pre-populate table 
1349
    */
1350
    for (ptr_statement= create_statements, x= 0; 
1351
         x < auto_generate_sql_unique_write_number; 
1352
         x++, ptr_statement= ptr_statement->next)
1353
    {
1354
      ptr_statement->next= build_insert_string();
1355
    }
1356
1357
    if (verbose >= 2)
1358
      printf("Building Query Statements for Auto\n");
1359
1360
    if (!opt_auto_generate_sql_type)
1361
      opt_auto_generate_sql_type= "mixed";
1362
1363
    query_statements_count= 
1364
      parse_option(opt_auto_generate_sql_type, &query_options, ',');
1365
1366
    query_statements= (statement **)my_malloc(sizeof(statement *) * query_statements_count,
1367
                                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1368
1369
    sql_type= query_options;
1370
    do
1371
    {
1372
      if (sql_type->string[0] == 'r')
1373
      {
1374
        if (verbose >= 2)
1375
          printf("Generating SELECT Statements for Auto\n");
1376
163 by Brian Aker
Merge Monty's code.
1377
        query_statements[sql_type_count]= build_select_string(false);
1 by brian
clean slate
1378
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1379
             x < auto_generate_sql_unique_query_number; 
1380
             x++, ptr_statement= ptr_statement->next)
1381
        {
163 by Brian Aker
Merge Monty's code.
1382
          ptr_statement->next= build_select_string(false);
1 by brian
clean slate
1383
        }
1384
      }
1385
      else if (sql_type->string[0] == 'k')
1386
      {
1387
        if (verbose >= 2)
1388
          printf("Generating SELECT for keys Statements for Auto\n");
1389
163 by Brian Aker
Merge Monty's code.
1390
        if ( auto_generate_sql_autoincrement == false &&
1391
             auto_generate_sql_guid_primary == false)
1 by brian
clean slate
1392
        {
1393
          fprintf(stderr,
1394
                  "%s: Can't perform key test without a primary key!\n",
1395
                  my_progname);
1396
          exit(1);
1397
        }
1398
163 by Brian Aker
Merge Monty's code.
1399
        query_statements[sql_type_count]= build_select_string(true);
1 by brian
clean slate
1400
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1401
             x < auto_generate_sql_unique_query_number; 
1402
             x++, ptr_statement= ptr_statement->next)
1403
        {
163 by Brian Aker
Merge Monty's code.
1404
          ptr_statement->next= build_select_string(true);
1 by brian
clean slate
1405
        }
1406
      }
1407
      else if (sql_type->string[0] == 'w')
1408
      {
1409
        /*
1410
          We generate a number of strings in case the engine is 
1411
          Archive (since strings which were identical one after another
1412
          would be too easily optimized).
1413
        */
1414
        if (verbose >= 2)
1415
          printf("Generating INSERT Statements for Auto\n");
1416
        query_statements[sql_type_count]= build_insert_string();
1417
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1418
             x < auto_generate_sql_unique_query_number; 
1419
             x++, ptr_statement= ptr_statement->next)
1420
        {
1421
          ptr_statement->next= build_insert_string();
1422
        }
1423
      }
1424
      else if (sql_type->string[0] == 'u')
1425
      {
163 by Brian Aker
Merge Monty's code.
1426
        if ( auto_generate_sql_autoincrement == false &&
1427
             auto_generate_sql_guid_primary == false)
1 by brian
clean slate
1428
        {
1429
          fprintf(stderr,
1430
                  "%s: Can't perform update test without a primary key!\n",
1431
                  my_progname);
1432
          exit(1);
1433
        }
1434
1435
        query_statements[sql_type_count]= build_update_string();
1436
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1437
             x < auto_generate_sql_unique_query_number; 
1438
             x++, ptr_statement= ptr_statement->next)
1439
        {
1440
          ptr_statement->next= build_update_string();
1441
        }
1442
      }
1443
      else /* Mixed mode is default */
1444
      {
1445
        int coin= 0;
1446
1447
        query_statements[sql_type_count]= build_insert_string();
1448
        /* 
1449
          This logic should be extended to do a more mixed load,
1450
          at the moment it results in "every other".
1451
        */
1452
        for (ptr_statement= query_statements[sql_type_count], x= 0; 
1453
             x < auto_generate_sql_unique_query_number; 
1454
             x++, ptr_statement= ptr_statement->next)
1455
        {
1456
          if (coin)
1457
          {
1458
            ptr_statement->next= build_insert_string();
1459
            coin= 0;
1460
          }
1461
          else
1462
          {
163 by Brian Aker
Merge Monty's code.
1463
            ptr_statement->next= build_select_string(true);
1 by brian
clean slate
1464
            coin= 1;
1465
          }
1466
        }
1467
      }
1468
      sql_type_count++;
1469
    } while (sql_type ? (sql_type= sql_type->next) : 0);
1470
  }
1471
  else
1472
  {
15 by brian
Fix for stat, NETWARE removal
1473
    if (create_string && !stat(create_string, &sbuf))
1 by brian
clean slate
1474
    {
1475
      File data_file;
1476
      if (!MY_S_ISREG(sbuf.st_mode))
1477
      {
1478
        fprintf(stderr,"%s: Create file was not a regular file\n",
1479
                my_progname);
1480
        exit(1);
1481
      }
1482
      if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1483
      {
1484
        fprintf(stderr,"%s: Could not open create file\n", my_progname);
1485
        exit(1);
1486
      }
1487
      tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1488
                              MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1489
      my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1490
      tmp_string[sbuf.st_size]= '\0';
1491
      my_close(data_file,MYF(0));
1492
      parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1493
      my_free(tmp_string, MYF(0));
1494
    }
1495
    else if (create_string)
1496
    {
1497
        parse_delimiter(create_string, &create_statements, delimiter[0]);
1498
    }
1499
1500
    /* Set this up till we fully support options on user generated queries */
1501
    if (user_supplied_query)
1502
    {
1503
      query_statements_count= 
1504
        parse_option("default", &query_options, ',');
1505
1506
      query_statements= (statement **)my_malloc(sizeof(statement *),
1507
                                                MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1508
    }
1509
15 by brian
Fix for stat, NETWARE removal
1510
    if (user_supplied_query && !stat(user_supplied_query, &sbuf))
1 by brian
clean slate
1511
    {
1512
      File data_file;
1513
      if (!MY_S_ISREG(sbuf.st_mode))
1514
      {
1515
        fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1516
                my_progname);
1517
        exit(1);
1518
      }
1519
      if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1520
      {
1521
        fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1522
        exit(1);
1523
      }
1524
      tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1525
                                    MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1526
      my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1527
      tmp_string[sbuf.st_size]= '\0';
1528
      my_close(data_file,MYF(0));
1529
      if (user_supplied_query)
1530
        actual_queries= parse_delimiter(tmp_string, &query_statements[0],
1531
                                        delimiter[0]);
1532
      my_free(tmp_string, MYF(0));
1533
    } 
1534
    else if (user_supplied_query)
1535
    {
1536
      actual_queries= parse_delimiter(user_supplied_query, &query_statements[0],
1537
                                      delimiter[0]);
1538
    }
1539
  }
1540
15 by brian
Fix for stat, NETWARE removal
1541
  if (user_supplied_pre_statements
1542
      && !stat(user_supplied_pre_statements, &sbuf))
1 by brian
clean slate
1543
  {
1544
    File data_file;
1545
    if (!MY_S_ISREG(sbuf.st_mode))
1546
    {
1547
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1548
              my_progname);
1549
      exit(1);
1550
    }
1551
    if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1552
    {
1553
      fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1554
      exit(1);
1555
    }
1556
    tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1557
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1558
    my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1559
    tmp_string[sbuf.st_size]= '\0';
1560
    my_close(data_file,MYF(0));
1561
    if (user_supplied_pre_statements)
1562
      (void)parse_delimiter(tmp_string, &pre_statements,
1563
                            delimiter[0]);
1564
    my_free(tmp_string, MYF(0));
1565
  } 
1566
  else if (user_supplied_pre_statements)
1567
  {
1568
    (void)parse_delimiter(user_supplied_pre_statements,
1569
                          &pre_statements,
1570
                          delimiter[0]);
1571
  }
1572
15 by brian
Fix for stat, NETWARE removal
1573
  if (user_supplied_post_statements
1574
      && !stat(user_supplied_post_statements, &sbuf))
1 by brian
clean slate
1575
  {
1576
    File data_file;
1577
    if (!MY_S_ISREG(sbuf.st_mode))
1578
    {
1579
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1580
              my_progname);
1581
      exit(1);
1582
    }
1583
    if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1584
    {
1585
      fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1586
      exit(1);
1587
    }
1588
    tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1589
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1590
    my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1591
    tmp_string[sbuf.st_size]= '\0';
1592
    my_close(data_file,MYF(0));
1593
    if (user_supplied_post_statements)
1594
      (void)parse_delimiter(tmp_string, &post_statements,
1595
                            delimiter[0]);
1596
    my_free(tmp_string, MYF(0));
1597
  } 
1598
  else if (user_supplied_post_statements)
1599
  {
1600
    (void)parse_delimiter(user_supplied_post_statements, &post_statements,
1601
                          delimiter[0]);
1602
  }
1603
1604
  if (verbose >= 2)
1605
    printf("Parsing engines to use.\n");
1606
1607
  if (default_engine)
1608
    parse_option(default_engine, &engine_options, ',');
1609
1610
  if (tty_password)
1611
    opt_password= get_tty_password(NullS);
142.1.2 by Patrick
All DBUG_x removed from client/
1612
  return(0);
1 by brian
clean slate
1613
}
1614
1615
1616
static int run_query(MYSQL *mysql, const char *query, int len)
1617
{
1618
  if (opt_only_print)
1619
  {
1620
    printf("%.*s;\n", len, query);
1621
    return 0;
1622
  }
1623
1624
  if (verbose >= 3)
1625
    printf("%.*s;\n", len, query);
1626
  return mysql_real_query(mysql, query, len);
1627
}
1628
1629
1630
static int
1631
generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1632
{
1633
  MYSQL_RES *result;
1634
  MYSQL_ROW row;
1635
  unsigned long long counter;
142.1.2 by Patrick
All DBUG_x removed from client/
1636
1 by brian
clean slate
1637
1638
  /* 
1639
    Blackhole is a special case, this allows us to test the upper end 
1640
    of the server during load runs.
1641
  */
1642
  if (opt_only_print || (engine_stmt && 
1643
                         strstr(engine_stmt->string, "blackhole")))
1644
  {
1645
    primary_keys_number_of= 1;
1646
    primary_keys= (char **)my_malloc((uint)(sizeof(char *) * 
1647
                                            primary_keys_number_of), 
1648
                                    MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1649
    /* Yes, we strdup a const string to simplify the interface */
1650
    primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0)); 
1651
  }
1652
  else
1653
  {
1654
    if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1655
    {
1656
      fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1657
              mysql_error(mysql));
1658
      exit(1);
1659
    }
1660
1661
    result= mysql_store_result(mysql);
1662
    primary_keys_number_of= mysql_num_rows(result);
1663
1664
    /* So why check this? Blackhole :) */
1665
    if (primary_keys_number_of)
1666
    {
1667
      /*
1668
        We create the structure and loop and create the items.
1669
      */
1670
      primary_keys= (char **)my_malloc((uint)(sizeof(char *) * 
1671
                                              primary_keys_number_of), 
1672
                                       MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1673
      row= mysql_fetch_row(result);
1674
      for (counter= 0; counter < primary_keys_number_of; 
1675
           counter++, row= mysql_fetch_row(result))
1676
        primary_keys[counter]= my_strdup(row[0], MYF(0));
1677
    }
1678
1679
    mysql_free_result(result);
1680
  }
1681
142.1.2 by Patrick
All DBUG_x removed from client/
1682
  return(0);
1 by brian
clean slate
1683
}
1684
1685
static int
1686
drop_primary_key_list(void)
1687
{
1688
  unsigned long long counter;
1689
1690
  if (primary_keys_number_of)
1691
  {
1692
    for (counter= 0; counter < primary_keys_number_of; counter++)
1693
      my_free(primary_keys[counter], MYF(0));
1694
1695
    my_free(primary_keys, MYF(0));
1696
  }
1697
1698
  return 0;
1699
}
1700
1701
static int
1702
create_schema(MYSQL *mysql, const char *db, statement *stmt, 
1703
              option_string *engine_stmt, stats *sptr)
1704
{
1705
  char query[HUGE_STRING_LENGTH];
1706
  statement *ptr;
1707
  statement *after_create;
1708
  int len;
151 by Brian Aker
Ulonglong to uint64_t
1709
  uint64_t count;
1 by brian
clean slate
1710
  struct timeval start_time, end_time;
142.1.2 by Patrick
All DBUG_x removed from client/
1711
1 by brian
clean slate
1712
1713
  gettimeofday(&start_time, NULL);
1714
1715
  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1716
1717
  if (verbose >= 2)
1718
    printf("Loading Pre-data\n");
1719
1720
  if (run_query(mysql, query, len))
1721
  {
1722
    fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1723
            mysql_error(mysql));
1724
    exit(1);
1725
  }
1726
  else
1727
  {
1728
    sptr->create_count++;
1729
  }
1730
1731
  if (opt_only_print)
1732
  {
1733
    printf("use %s;\n", db);
1734
  }
1735
  else
1736
  {
1737
    if (verbose >= 3)
1738
      printf("%s;\n", query);
1739
1740
    if (mysql_select_db(mysql,  db))
1741
    {
1742
      fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1743
              mysql_error(mysql));
1744
      exit(1);
1745
    }
1746
    sptr->create_count++;
1747
  }
1748
1749
  if (engine_stmt)
1750
  {
1751
    len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1752
                  engine_stmt->string);
1753
    if (run_query(mysql, query, len))
1754
    {
1755
      fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
1756
              mysql_error(mysql));
1757
      exit(1);
1758
    }
1759
    sptr->create_count++;
1760
  }
1761
1762
  count= 0;
1763
  after_create= stmt;
1764
1765
limit_not_met:
1766
  for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1767
  {
1768
    if (auto_generate_sql && ( auto_generate_sql_number == count))
1769
      break;
1770
1771
    if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1772
    {
1773
      char buffer[HUGE_STRING_LENGTH];
1774
1775
      snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string, 
1776
               engine_stmt->option);
1777
      if (run_query(mysql, buffer, strlen(buffer)))
1778
      {
1779
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1780
                my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1781
        if (!opt_ignore_sql_errors)
1782
          exit(1);
1783
      }
1784
      sptr->create_count++;
1785
    }
1786
    else
1787
    {
1788
      if (run_query(mysql, ptr->string, ptr->length))
1789
      {
1790
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1791
                my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1792
        if (!opt_ignore_sql_errors)
1793
          exit(1);
1794
      }
1795
      sptr->create_count++;
1796
    }
1797
  }
1798
1799
  if (auto_generate_sql && (auto_generate_sql_number > count ))
1800
  {
1801
    /* Special case for auto create, we don't want to create tables twice */
1802
    after_create= stmt->next;
1803
    goto limit_not_met;
1804
  }
1805
1806
  gettimeofday(&end_time, NULL);
1807
1808
  sptr->create_timing= timedif(end_time, start_time);
1809
142.1.2 by Patrick
All DBUG_x removed from client/
1810
  return(0);
1 by brian
clean slate
1811
}
1812
1813
static int
1814
drop_schema(MYSQL *mysql, const char *db)
1815
{
1816
  char query[HUGE_STRING_LENGTH];
1817
  int len;
142.1.2 by Patrick
All DBUG_x removed from client/
1818
1 by brian
clean slate
1819
  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1820
1821
  if (run_query(mysql, query, len))
1822
  {
1823
    fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1824
            my_progname, db, mysql_error(mysql));
1825
    exit(1);
1826
  }
1827
1828
1829
142.1.2 by Patrick
All DBUG_x removed from client/
1830
  return(0);
1 by brian
clean slate
1831
}
1832
1833
static int
1834
run_statements(MYSQL *mysql, statement *stmt) 
1835
{
1836
  statement *ptr;
1837
  MYSQL_RES *result;
142.1.2 by Patrick
All DBUG_x removed from client/
1838
1 by brian
clean slate
1839
1840
  for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1841
  {
1842
    if (run_query(mysql, ptr->string, ptr->length))
1843
    {
1844
      fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1845
              my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1846
      exit(1);
1847
    }
1848
    if (!opt_only_print)
1849
    {
1850
      if (mysql_field_count(mysql))
1851
      {
1852
        result= mysql_store_result(mysql);
1853
        mysql_free_result(result);
1854
      }
1855
    }
1856
  }
1857
142.1.2 by Patrick
All DBUG_x removed from client/
1858
  return(0);
1 by brian
clean slate
1859
}
1860
1861
static int
151 by Brian Aker
Ulonglong to uint64_t
1862
run_scheduler(stats *sptr, statement **stmts, uint concur, uint64_t limit)
1 by brian
clean slate
1863
{
1864
  uint x;
1865
  uint y;
1866
  unsigned int real_concurrency;
1867
  struct timeval start_time, end_time;
1868
  option_string *sql_type;
1869
  thread_context *con;
1870
  pthread_t mainthread;            /* Thread descriptor */
1871
  pthread_attr_t attr;          /* Thread attributes */
142.1.2 by Patrick
All DBUG_x removed from client/
1872
1 by brian
clean slate
1873
1874
  pthread_attr_init(&attr);
1875
  pthread_attr_setdetachstate(&attr,
1876
		  PTHREAD_CREATE_DETACHED);
1877
1878
  pthread_mutex_lock(&counter_mutex);
1879
  thread_counter= 0;
1880
1881
  pthread_mutex_lock(&sleeper_mutex);
1882
  master_wakeup= 1;
1883
  pthread_mutex_unlock(&sleeper_mutex);
1884
1885
  real_concurrency= 0;
1886
1887
  for (y= 0, sql_type= query_options; 
1888
       y < query_statements_count; 
1889
       y++, sql_type= sql_type->next)
1890
  {
1891
    unsigned int options_loop= 1;
1892
1893
    if (sql_type->option)
1894
    {
1895
      options_loop= strtol(sql_type->option, 
1896
                           (char **)NULL, 10);
1897
      options_loop= options_loop ? options_loop : 1;
1898
    }
1899
1900
    while (options_loop--)
1901
      for (x= 0; x < concur; x++)
1902
      {
1903
        con= (thread_context *)my_malloc(sizeof(thread_context), MYF(0));
1904
        con->stmt= stmts[y];
1905
        con->limit= limit;
1906
1907
        real_concurrency++;
1908
        /* now you create the thread */
1909
        if (pthread_create(&mainthread, &attr, run_task, 
1910
                           (void *)con) != 0)
1911
        {
1912
          fprintf(stderr,"%s: Could not create thread\n", my_progname);
1913
          exit(1);
1914
        }
1915
        thread_counter++;
1916
      }
1917
  }
1918
1919
  /* 
1920
    The timer_thread belongs to all threads so it too obeys the wakeup 
1921
    call that run tasks obey.
1922
  */
1923
  if (opt_timer_length)
1924
  {
1925
    pthread_mutex_lock(&timer_alarm_mutex);
163 by Brian Aker
Merge Monty's code.
1926
    timer_alarm= true;
1 by brian
clean slate
1927
    pthread_mutex_unlock(&timer_alarm_mutex);
1928
1929
    if (pthread_create(&mainthread, &attr, timer_thread, 
1930
                       (void *)&opt_timer_length) != 0)
1931
    {
1932
      fprintf(stderr,"%s: Could not create timer thread\n", my_progname);
1933
      exit(1);
1934
    }
1935
  }
1936
1937
  pthread_mutex_unlock(&counter_mutex);
1938
  pthread_attr_destroy(&attr);
1939
1940
  pthread_mutex_lock(&sleeper_mutex);
1941
  master_wakeup= 0;
1942
  pthread_mutex_unlock(&sleeper_mutex);
1943
  pthread_cond_broadcast(&sleep_threshhold);
1944
1945
  gettimeofday(&start_time, NULL);
1946
1947
  /*
1948
    We loop until we know that all children have cleaned up.
1949
  */
1950
  pthread_mutex_lock(&counter_mutex);
1951
  while (thread_counter)
1952
  {
1953
    struct timespec abstime;
1954
1955
    set_timespec(abstime, 3);
1956
    pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1957
  }
1958
  pthread_mutex_unlock(&counter_mutex);
1959
1960
  gettimeofday(&end_time, NULL);
1961
1962
1963
  sptr->timing= timedif(end_time, start_time);
1964
  sptr->users= concur;
1965
  sptr->real_users= real_concurrency;
1966
  sptr->rows= limit;
1967
142.1.2 by Patrick
All DBUG_x removed from client/
1968
  return(0);
1 by brian
clean slate
1969
}
1970
1971
1972
pthread_handler_t timer_thread(void *p)
1973
{
1974
  uint *timer_length= (uint *)p;
1975
  struct timespec abstime;
1976
142.1.2 by Patrick
All DBUG_x removed from client/
1977
1 by brian
clean slate
1978
1979
  if (mysql_thread_init())
1980
  {
1981
    fprintf(stderr,"%s: mysql_thread_init() failed.\n",
1982
            my_progname);
1983
    exit(1);
1984
  }
1985
1986
  /* 
1987
    We lock around the initial call in case were we in a loop. This 
1988
    also keeps the value properly syncronized across call threads.
1989
  */
1990
  pthread_mutex_lock(&sleeper_mutex);
1991
  while (master_wakeup)
1992
  {
1993
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
1994
  }
1995
  pthread_mutex_unlock(&sleeper_mutex);
1996
1997
  set_timespec(abstime, *timer_length);
1998
1999
  pthread_mutex_lock(&timer_alarm_mutex);
2000
  pthread_cond_timedwait(&timer_alarm_threshold, &timer_alarm_mutex, &abstime);
2001
  pthread_mutex_unlock(&timer_alarm_mutex);
2002
2003
  pthread_mutex_lock(&timer_alarm_mutex);
163 by Brian Aker
Merge Monty's code.
2004
  timer_alarm= false;
1 by brian
clean slate
2005
  pthread_mutex_unlock(&timer_alarm_mutex);
2006
2007
  mysql_thread_end();
142.1.2 by Patrick
All DBUG_x removed from client/
2008
  return(0);
1 by brian
clean slate
2009
}
2010
2011
pthread_handler_t run_task(void *p)
2012
{
151 by Brian Aker
Ulonglong to uint64_t
2013
  uint64_t counter= 0, queries;
2014
  uint64_t detach_counter;
1 by brian
clean slate
2015
  unsigned int commit_counter;
2016
  MYSQL mysql;
2017
  MYSQL_RES *result;
2018
  MYSQL_ROW row;
2019
  statement *ptr;
2020
  thread_context *con= (thread_context *)p;
2021
2022
  if (mysql_thread_init())
2023
  {
2024
    fprintf(stderr,"%s: mysql_thread_init() failed.\n",
2025
            my_progname);
2026
    exit(1);
2027
  }
2028
2029
  pthread_mutex_lock(&sleeper_mutex);
2030
  while (master_wakeup)
2031
  {
2032
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2033
  }
2034
  pthread_mutex_unlock(&sleeper_mutex);
2035
163 by Brian Aker
Merge Monty's code.
2036
  slap_connect(&mysql, true);
1 by brian
clean slate
2037
2038
  if (verbose >= 3)
2039
    printf("connected!\n");
2040
  queries= 0;
2041
2042
  commit_counter= 0;
2043
  if (commit_rate)
2044
    run_query(&mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
2045
2046
limit_not_met:
2047
    for (ptr= con->stmt, detach_counter= 0; 
2048
         ptr && ptr->length; 
2049
         ptr= ptr->next, detach_counter++)
2050
    {
2051
      if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
2052
      {
2053
        slap_close(&mysql);
163 by Brian Aker
Merge Monty's code.
2054
        slap_connect(&mysql, true);
1 by brian
clean slate
2055
      }
2056
2057
      /* 
2058
        We have to execute differently based on query type. This should become a function.
2059
      */
2060
      if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
2061
          (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
2062
      {
2063
        int length;
2064
        unsigned int key_val;
2065
        char *key;
2066
        char buffer[HUGE_STRING_LENGTH];
2067
2068
        /* 
2069
          This should only happen if some sort of new engine was
2070
          implemented that didn't properly handle UPDATEs.
2071
2072
          Just in case someone runs this under an experimental engine we don't
2073
          want a crash so the if() is placed here.
2074
        */
142.1.2 by Patrick
All DBUG_x removed from client/
2075
        assert(primary_keys_number_of);
1 by brian
clean slate
2076
        if (primary_keys_number_of)
2077
        {
2078
          key_val= (unsigned int)(random() % primary_keys_number_of);
2079
          key= primary_keys[key_val];
2080
142.1.2 by Patrick
All DBUG_x removed from client/
2081
          assert(key);
1 by brian
clean slate
2082
2083
          length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", 
2084
                           (int)ptr->length, ptr->string, key);
2085
2086
          if (run_query(&mysql, buffer, length))
2087
          {
2088
            fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2089
                    my_progname, (uint)length, buffer, mysql_error(&mysql));
2090
            exit(1);
2091
          }
2092
        }
2093
      }
2094
      else
2095
      {
2096
        if (run_query(&mysql, ptr->string, ptr->length))
2097
        {
2098
          fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2099
                  my_progname, (uint)ptr->length, ptr->string, mysql_error(&mysql));
2100
          exit(1);
2101
        }
2102
      }
2103
2104
      if (!opt_only_print)
2105
      {
2106
        do
2107
        {
2108
          if (mysql_field_count(&mysql))
2109
          {
2110
            result= mysql_store_result(&mysql);
2111
            while ((row = mysql_fetch_row(result)))
2112
              counter++;
2113
            mysql_free_result(result);
2114
          }
2115
        } while(mysql_next_result(&mysql) == 0);
2116
      }
2117
      queries++;
2118
2119
      if (commit_rate && (++commit_counter == commit_rate))
2120
      {
2121
        commit_counter= 0;
2122
        run_query(&mysql, "COMMIT", strlen("COMMIT"));
2123
      }
2124
2125
      /* If the timer is set, and the alarm is not active then end */
163 by Brian Aker
Merge Monty's code.
2126
      if (opt_timer_length && timer_alarm == false)
1 by brian
clean slate
2127
        goto end;
2128
2129
      /* If limit has been reached, and we are not in a timer_alarm just end */
163 by Brian Aker
Merge Monty's code.
2130
      if (con->limit && queries == con->limit && timer_alarm == false)
1 by brian
clean slate
2131
        goto end;
2132
    }
2133
163 by Brian Aker
Merge Monty's code.
2134
    if (opt_timer_length && timer_alarm == true)
1 by brian
clean slate
2135
      goto limit_not_met;
2136
2137
    if (con->limit && queries < con->limit)
2138
      goto limit_not_met;
2139
2140
2141
end:
2142
  if (commit_rate)
2143
    run_query(&mysql, "COMMIT", strlen("COMMIT"));
2144
2145
  slap_close(&mysql);
2146
2147
  pthread_mutex_lock(&counter_mutex);
2148
  thread_counter--;
2149
  pthread_cond_signal(&count_threshhold);
2150
  pthread_mutex_unlock(&counter_mutex);
2151
2152
  my_free(con, MYF(0));
2153
2154
  mysql_thread_end();
142.1.2 by Patrick
All DBUG_x removed from client/
2155
  return(0);
1 by brian
clean slate
2156
}
2157
2158
/*
2159
  Parse records from comma seperated string. : is a reserved character and is used for options
2160
  on variables.
2161
*/
2162
uint
2163
parse_option(const char *origin, option_string **stmt, char delm)
2164
{
2165
  char *string;
2166
  char *begin_ptr;
2167
  char *end_ptr;
2168
  option_string **sptr= stmt;
2169
  option_string *tmp;
2170
  uint length= strlen(origin);
2171
  uint count= 0; /* We know that there is always one */
2172
2173
  end_ptr= (char *)origin + length;
2174
2175
  tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
2176
                                         MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2177
2178
  for (begin_ptr= (char *)origin;
2179
       begin_ptr != end_ptr;
2180
       tmp= tmp->next)
2181
  {
2182
    char buffer[HUGE_STRING_LENGTH];
2183
    char *buffer_ptr;
2184
2185
    bzero(buffer, HUGE_STRING_LENGTH);
2186
2187
    string= strchr(begin_ptr, delm); 
2188
2189
    if (string)
2190
    {
2191
      memcpy(buffer, begin_ptr, string - begin_ptr);
2192
      begin_ptr= string+1;
2193
    }
2194
    else
2195
    {
2196
      size_t length= strlen(begin_ptr);
2197
      memcpy(buffer, begin_ptr, length);
2198
      begin_ptr= end_ptr;
2199
    }
2200
2201
    if ((buffer_ptr= strchr(buffer, ':')))
2202
    {
2203
      /* Set a null so that we can get strlen() correct later on */
2204
      buffer_ptr[0]= 0;
2205
      buffer_ptr++;
2206
2207
      /* Move past the : and the first string */
2208
      tmp->option_length= strlen(buffer_ptr);
2209
      tmp->option= my_strndup(buffer_ptr, (uint)tmp->option_length,
2210
                              MYF(MY_FAE));
2211
    }
2212
2213
    tmp->string= my_strndup(buffer, strlen(buffer), MYF(MY_FAE));
2214
    tmp->length= strlen(buffer);
2215
2216
    if (isspace(*begin_ptr))
2217
      begin_ptr++;
2218
2219
    count++;
2220
2221
    if (begin_ptr != end_ptr)
2222
      tmp->next= (option_string *)my_malloc(sizeof(option_string),
2223
                                            MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2224
  }
2225
2226
  return count;
2227
}
2228
2229
2230
/*
2231
  Raw parsing interface. If you want the slap specific parser look at
2232
  parse_option.
2233
*/
2234
uint
2235
parse_delimiter(const char *script, statement **stmt, char delm)
2236
{
2237
  char *retstr;
2238
  char *ptr= (char *)script;
2239
  statement **sptr= stmt;
2240
  statement *tmp;
2241
  uint length= strlen(script);
2242
  uint count= 0; /* We know that there is always one */
2243
2244
  for (tmp= *sptr= (statement *)my_malloc(sizeof(statement),
2245
                                          MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2246
       (retstr= strchr(ptr, delm)); 
2247
       tmp->next=  (statement *)my_malloc(sizeof(statement),
2248
                                          MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2249
       tmp= tmp->next)
2250
  {
2251
    count++;
2252
    tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE));
2253
    tmp->length= (size_t)(retstr - ptr);
2254
    ptr+= retstr - ptr + 1;
2255
    if (isspace(*ptr))
2256
      ptr++;
2257
  }
2258
2259
  if (ptr != script+length)
2260
  {
2261
    tmp->string= my_strndup(ptr, (uint)((script + length) - ptr), 
2262
                                       MYF(MY_FAE));
2263
    tmp->length= (size_t)((script + length) - ptr);
2264
    count++;
2265
  }
2266
2267
  return count;
2268
}
2269
2270
2271
/*
2272
  Parse comma is different from parse_delimeter in that it parses
2273
  number ranges from a comma seperated string.
2274
  In restrospect, this is a lousy name from this function.
2275
*/
2276
uint
2277
parse_comma(const char *string, uint **range)
2278
{
2279
  uint count= 1,x; /* We know that there is always one */
2280
  char *retstr;
2281
  char *ptr= (char *)string;
2282
  uint *nptr;
2283
2284
  for (;*ptr; ptr++)
2285
    if (*ptr == ',') count++;
2286
  
2287
  /* One extra spot for the NULL */
2288
  nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1), 
2289
                                  MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2290
2291
  ptr= (char *)string;
2292
  x= 0;
2293
  while ((retstr= strchr(ptr,',')))
2294
  {
2295
    nptr[x++]= atoi(ptr);
2296
    ptr+= retstr - ptr + 1;
2297
  }
2298
  nptr[x++]= atoi(ptr);
2299
2300
  return count;
2301
}
2302
2303
void
2304
print_conclusions(conclusions *con)
2305
{
2306
  printf("Benchmark\n");
2307
  if (con->engine)
2308
      printf("\tRunning for engine %s\n", con->engine);
2309
  if (opt_label || opt_auto_generate_sql_type)
2310
  {
2311
    const char *ptr= opt_auto_generate_sql_type ? opt_auto_generate_sql_type : "query";
2312
    printf("\tLoad: %s\n", opt_label ? opt_label : ptr);
2313
  }
2314
  printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
2315
         con->create_avg_timing / 1000, con->create_avg_timing % 1000);
2316
  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2317
         con->avg_timing / 1000, con->avg_timing % 1000);
2318
  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2319
         con->min_timing / 1000, con->min_timing % 1000);
2320
  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2321
         con->max_timing / 1000, con->max_timing % 1000);
2322
  printf("\tTotal time for tests: %ld.%03ld seconds\n", 
2323
         con->sum_of_time / 1000, con->sum_of_time % 1000);
2324
  printf("\tStandard Deviation: %ld.%03ld\n", con->std_dev / 1000, con->std_dev % 1000);
2325
  printf("\tNumber of queries in create queries: %llu\n", con->create_count);
2326
  printf("\tNumber of clients running queries: %u/%u\n", 
2327
         con->users, con->real_users);
2328
  printf("\tNumber of times test was run: %u\n", iterations);
2329
  printf("\tAverage number of queries per client: %llu\n", con->avg_rows); 
2330
  printf("\n");
2331
}
2332
2333
void
2334
print_conclusions_csv(conclusions *con)
2335
{
2336
  unsigned int x;
2337
  char buffer[HUGE_STRING_LENGTH];
2338
  char label_buffer[HUGE_STRING_LENGTH];
2339
  size_t string_len;
2340
2341
  bzero(label_buffer, HUGE_STRING_LENGTH);
2342
2343
  if (opt_label)
2344
  {
2345
    string_len= strlen(opt_label);
2346
2347
    for (x= 0; x < string_len; x++)
2348
    {
2349
      if (opt_label[x] == ',')
2350
        label_buffer[x]= '-';
2351
      else
2352
        label_buffer[x]= opt_label[x] ;
2353
    }
2354
  } 
2355
  else if (opt_auto_generate_sql_type)
2356
  {
2357
    string_len= strlen(opt_auto_generate_sql_type);
2358
2359
    for (x= 0; x < string_len; x++)
2360
    {
2361
      if (opt_auto_generate_sql_type[x] == ',')
2362
        label_buffer[x]= '-';
2363
      else
2364
        label_buffer[x]= opt_auto_generate_sql_type[x] ;
2365
    }
2366
  }
2367
  else
2368
    snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2369
2370
  snprintf(buffer, HUGE_STRING_LENGTH, 
2371
           "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%u,%u,%u,%llu\n",
2372
           con->engine ? con->engine : "", /* Storage engine we ran against */
2373
           label_buffer, /* Load type */
2374
           con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2375
           con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2376
           con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2377
           con->sum_of_time / 1000, con->sum_of_time % 1000, /* Total time */
2378
           con->std_dev / 1000, con->std_dev % 1000, /* Standard Deviation */
2379
           iterations, /* Iterations */
2380
           con->users, /* Children used max_timing */
2381
           con->real_users, /* Children used max_timing */
2382
           con->avg_rows  /* Queries run */
2383
          );
2384
  my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2385
}
2386
2387
void
2388
generate_stats(conclusions *con, option_string *eng, stats *sptr)
2389
{
2390
  stats *ptr;
2391
  unsigned int x;
2392
2393
  con->min_timing= sptr->timing; 
2394
  con->max_timing= sptr->timing;
2395
  con->min_rows= sptr->rows;
2396
  con->max_rows= sptr->rows;
2397
  
2398
  /* At the moment we assume uniform */
2399
  con->users= sptr->users;
2400
  con->real_users= sptr->real_users;
2401
  con->avg_rows= sptr->rows;
2402
  
2403
  /* With no next, we know it is the last element that was malloced */
2404
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2405
  {
2406
    con->avg_timing+= ptr->timing;
2407
2408
    if (ptr->timing > con->max_timing)
2409
      con->max_timing= ptr->timing;
2410
    if (ptr->timing < con->min_timing)
2411
      con->min_timing= ptr->timing;
2412
  }
2413
  con->sum_of_time= con->avg_timing;
2414
  con->avg_timing= con->avg_timing/iterations;
2415
2416
  if (eng && eng->string)
2417
    con->engine= eng->string;
2418
  else
2419
    con->engine= NULL;
2420
2421
  standard_deviation(con, sptr);
2422
2423
  /* Now we do the create time operations */
2424
  con->create_min_timing= sptr->create_timing; 
2425
  con->create_max_timing= sptr->create_timing;
2426
  
2427
  /* At the moment we assume uniform */
2428
  con->create_count= sptr->create_count;
2429
  
2430
  /* With no next, we know it is the last element that was malloced */
2431
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2432
  {
2433
    con->create_avg_timing+= ptr->create_timing;
2434
2435
    if (ptr->create_timing > con->create_max_timing)
2436
      con->create_max_timing= ptr->create_timing;
2437
    if (ptr->create_timing < con->create_min_timing)
2438
      con->create_min_timing= ptr->create_timing;
2439
  }
2440
  con->create_avg_timing= con->create_avg_timing/iterations;
2441
}
2442
2443
void
2444
option_cleanup(option_string *stmt)
2445
{
2446
  option_string *ptr, *nptr;
2447
  if (!stmt)
2448
    return;
2449
2450
  for (ptr= stmt; ptr; ptr= nptr)
2451
  {
2452
    nptr= ptr->next;
2453
    if (ptr->string)
2454
      my_free(ptr->string, MYF(0)); 
2455
    if (ptr->option)
2456
      my_free(ptr->option, MYF(0)); 
2457
    my_free(ptr, MYF(0));
2458
  }
2459
}
2460
2461
void
2462
statement_cleanup(statement *stmt)
2463
{
2464
  statement *ptr, *nptr;
2465
  if (!stmt)
2466
    return;
2467
2468
  for (ptr= stmt; ptr; ptr= nptr)
2469
  {
2470
    nptr= ptr->next;
2471
    if (ptr->string)
2472
      my_free(ptr->string, MYF(0)); 
2473
    my_free(ptr, MYF(0));
2474
  }
2475
}
2476
2477
void 
2478
slap_close(MYSQL *mysql)
2479
{
2480
  if (opt_only_print) 
2481
    return;
2482
2483
  mysql_close(mysql);
2484
}
2485
2486
void 
143 by Brian Aker
Bool cleanup.
2487
slap_connect(MYSQL *mysql, bool connect_to_schema)
1 by brian
clean slate
2488
{
2489
  /* Connect to server */
2490
  static ulong connection_retry_sleep= 100000; /* Microseconds */
2491
  int x, connect_error= 1;
2492
2493
  if (opt_only_print) 
2494
    return;
2495
2496
  if (opt_delayed_start)
2497
    my_sleep(random()%opt_delayed_start);
2498
2499
  mysql_init(mysql);
2500
2501
  if (opt_compress)
2502
    mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
2503
  /* We always do opt_protocol to TCP/IP */
2504
  mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
2505
  mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
2506
2507
  for (x= 0; x < 10; x++)
2508
  {
2509
2510
2511
    if (mysql_real_connect(mysql, host, user, opt_password,
2512
                           connect_to_schema ? create_schema_string : NULL,
2513
                           opt_mysql_port,
2514
                           opt_mysql_unix_port,
2515
                           connect_flags))
2516
    {
2517
      /* Connect suceeded */
2518
      connect_error= 0;
2519
      break;
2520
    }
2521
    my_sleep(connection_retry_sleep);
2522
  }
2523
  if (connect_error)
2524
  {
2525
    fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2526
            my_progname, mysql_errno(mysql), mysql_error(mysql));
2527
    exit(1);
2528
  }
2529
2530
  return;
2531
}
2532
2533
void 
2534
standard_deviation (conclusions *con, stats *sptr)
2535
{
2536
  unsigned int x;
2537
  long int sum_of_squares;
2538
  double catch;
2539
  stats *ptr;
2540
2541
  if (iterations == 1 || iterations == 0)
2542
  {
2543
    con->std_dev= 0;
2544
    return;
2545
  }
2546
2547
  for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2548
  {
2549
    long int deviation;
2550
2551
    deviation= ptr->timing - con->avg_timing;
2552
    sum_of_squares+= deviation*deviation;
2553
  }
2554
2555
  catch= sqrt((double)(sum_of_squares/(iterations -1)));
2556
  con->std_dev= (long int)catch;
2557
}