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