~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/mysqlslap.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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