~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to client/mysqlslap.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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