~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

  • Committer: Monty Taylor
  • Date: 2010-04-15 19:14:53 UTC
  • mto: This revision was merged to the branch mainline in revision 1476.
  • Revision ID: mordred@inaugust.com-20100415191453-ril2x8qdo78fny9w
Replaced test_authz with a plugin implementing a hard-coded simple
multi-tennancy policy. The policy describes:
- A root user exists which can do anything
- A user may only see a schema that is named the same has his user name
- A user may see data_dictionary and information_schema (data_dictionary
  required for show databases to work)

This way, we can more clearly test the results of the authorization
interface while providing an optional plugin that is actually useful to some
human.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 * 
4
 
 *  Copyright (C) 2010 Vijay Samuel
 
3
 *
5
4
 *  Copyright (C) 2008 MySQL
6
5
 *
7
6
 *  This program is free software; you can redistribute it and/or modify
45
44
#include <map>
46
45
#include <string>
47
46
#include <sstream>
48
 
#include <fstream>
49
47
#include <iostream>
50
48
#include <vector>
51
49
#include <algorithm>
56
54
#include <sys/stat.h>
57
55
#include <sys/types.h>
58
56
#include <fcntl.h>
59
 
#include <boost/program_options.hpp>
60
57
 
61
58
#include PCRE_HEADER
62
59
 
63
60
#include <stdarg.h>
64
 
#include <boost/unordered_map.hpp>
 
61
#include <drizzled/unordered_map.h>
 
62
 
 
63
#include "errname.h"
65
64
 
66
65
/* Added this for string translation. */
67
66
#include "drizzled/gettext.h"
68
67
#include "drizzled/drizzle_time.h"
69
68
#include "drizzled/charset.h"
70
 
#include <drizzled/configmake.h>
71
69
 
72
70
#ifndef DRIZZLE_RETURN_SERVER_GONE
73
71
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
74
72
#endif
75
 
namespace po= boost::program_options;
 
73
 
76
74
using namespace std;
77
75
using namespace drizzled;
78
76
 
88
86
#define QUERY_SEND_FLAG  1
89
87
#define QUERY_REAP_FLAG  2
90
88
 
91
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
92
89
ErrorCodes global_error_names;
93
90
 
94
91
enum {
98
95
};
99
96
 
100
97
static int record= 0, opt_sleep= -1;
101
 
static char *opt_pass= NULL;
102
 
const char *unix_sock= NULL;
 
98
static char *opt_db= NULL, *opt_pass= NULL;
 
99
const char *opt_user= NULL, *opt_host= NULL, *unix_sock= NULL,
 
100
           *opt_basedir= "./";
 
101
const char *opt_logdir= "";
 
102
const char *opt_include= NULL, *opt_charsets_dir;
 
103
const char *opt_testdir= NULL;
103
104
static uint32_t opt_port= 0;
104
 
static uint32_t opt_max_connect_retries;
 
105
static int opt_max_connect_retries;
105
106
static bool silent= false, verbose= false;
 
107
static bool tty_password= false;
106
108
static bool opt_mark_progress= false;
107
109
static bool parsing_disabled= false;
108
110
static bool display_result_vertically= false,
113
115
static bool abort_on_error= true;
114
116
static bool server_initialized= false;
115
117
static bool is_windows= false;
116
 
static bool use_drizzle_protocol= false;
 
118
static bool opt_mysql= false;
 
119
static char **default_argv;
 
120
static const char *load_default_groups[]= { "drizzletest", "client", 0 };
117
121
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
118
122
 
119
 
std::string opt_basedir,
120
 
  opt_charsets_dir,
121
 
  opt_db,
122
 
  opt_host,
123
 
  opt_include,
124
 
  opt_testdir,
125
 
  opt_logdir,
126
 
  password,
127
 
  opt_password,
128
 
  result_file_name,
129
 
  opt_user,
130
 
  opt_protocol;
131
 
 
132
123
static uint32_t start_lineno= 0; /* Start line of current command */
133
124
 
134
125
/* Number of lines of the result to include in failure report */
198
189
master_pos_st master_pos;
199
190
 
200
191
/* if set, all results are concated and compared against this file */
 
192
const char *result_file_name= NULL;
201
193
 
202
194
typedef struct st_var
203
195
{
216
208
VAR var_reg[10];
217
209
 
218
210
 
219
 
boost::unordered_map<string, VAR *> var_hash;
 
211
unordered_map<string, VAR *> var_hash;
220
212
 
221
213
struct st_connection
222
214
{
782
774
    const struct command_arg *arg= &args[i];
783
775
    arg->ds->clear();
784
776
 
785
 
    bool known_arg_type= true;
786
777
    switch (arg->type) {
787
778
      /* A string */
788
779
    case ARG_STRING:
817
808
      break;
818
809
 
819
810
    default:
820
 
      known_arg_type= false;
 
811
      assert("Unknown argument type");
821
812
      break;
822
813
    }
823
 
    assert(known_arg_type);
824
814
 
825
815
    /* Check required arg */
826
816
    if (arg->ds->length() == 0 && arg->required)
930
920
 
931
921
  free_all_replace();
932
922
  free(opt_pass);
 
923
  internal::free_defaults(default_argv);
933
924
 
934
925
  return;
935
926
}
1011
1002
  }
1012
1003
 
1013
1004
  /* Dump the result that has been accumulated so far to .log file */
1014
 
  if (! result_file_name.empty() && ds_res.length())
 
1005
  if (result_file_name && ds_res.length())
1015
1006
    dump_result_to_log_file(ds_res.c_str(), ds_res.length());
1016
1007
 
1017
1008
  /* Dump warning messages */
1018
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
1009
  if (result_file_name && ds_warning_messages.length())
1019
1010
    dump_warning_messages();
1020
1011
 
1021
1012
  /*
1363
1354
  if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1364
1355
  {
1365
1356
    internal::my_close(fd, MYF(0));
1366
 
    if (! opt_testdir.empty())
 
1357
    if (opt_testdir != NULL)
1367
1358
    {
1368
1359
      tmpfile= opt_testdir;
1369
1360
      if (tmpfile[tmpfile.length()] != '/')
1461
1452
  int fd;
1462
1453
  char temp_file_path[FN_REFLEN];
1463
1454
 
1464
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
 
1455
  if ((fd= internal::create_temp_file(temp_file_path, NULL,
1465
1456
                            "tmp", MYF(MY_WME))) < 0)
1466
1457
    die("Failed to create temporary file for ds");
1467
1458
 
1503
1494
  const char* mess= "Result content mismatch\n";
1504
1495
 
1505
1496
 
1506
 
  assert(result_file_name.c_str());
1507
 
 
1508
 
  if (access(result_file_name.c_str(), F_OK) != 0)
1509
 
    die("The specified result file does not exist: '%s'", result_file_name.c_str());
1510
 
 
1511
 
  switch (string_cmp(ds, result_file_name.c_str())) {
 
1497
  assert(result_file_name);
 
1498
 
 
1499
  if (access(result_file_name, F_OK) != 0)
 
1500
    die("The specified result file does not exist: '%s'", result_file_name);
 
1501
 
 
1502
  switch (string_cmp(ds, result_file_name)) {
1512
1503
  case RESULT_OK:
1513
1504
    break; /* ok */
1514
1505
  case RESULT_LENGTH_MISMATCH:
1522
1513
    */
1523
1514
    char reject_file[FN_REFLEN];
1524
1515
    size_t reject_length;
1525
 
    internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
 
1516
    internal::dirname_part(reject_file, result_file_name, &reject_length);
1526
1517
 
1527
1518
    if (access(reject_file, W_OK) == 0)
1528
1519
    {
1529
1520
      /* Result file directory is writable, save reject file there */
1530
 
      internal::fn_format(reject_file, result_file_name.c_str(), NULL,
 
1521
      internal::fn_format(reject_file, result_file_name, NULL,
1531
1522
                ".reject", MY_REPLACE_EXT);
1532
1523
    }
1533
1524
    else
1534
1525
    {
1535
1526
      /* Put reject file in opt_logdir */
1536
 
      internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
 
1527
      internal::fn_format(reject_file, result_file_name, opt_logdir,
1537
1528
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1538
1529
    }
1539
1530
    str_to_file(reject_file, ds->c_str(), ds->length());
1540
1531
 
1541
1532
    ds->erase(); /* Don't create a .log file */
1542
1533
 
1543
 
    show_diff(NULL, result_file_name.c_str(), reject_file);
 
1534
    show_diff(NULL, result_file_name, reject_file);
1544
1535
    die("%s",mess);
1545
1536
    break;
1546
1537
  }
1712
1703
      die("Too long variable name: %s", save_var_name);
1713
1704
 
1714
1705
    string save_var_name_str(save_var_name, length);
1715
 
    boost::unordered_map<string, VAR*>::iterator iter=
 
1706
    unordered_map<string, VAR*>::iterator iter=
1716
1707
      var_hash.find(save_var_name_str);
1717
1708
    if (iter == var_hash.end())
1718
1709
    {
1750
1741
static VAR *var_obtain(const char *name, int len)
1751
1742
{
1752
1743
  string var_name(name, len);
1753
 
  boost::unordered_map<string, VAR*>::iterator iter=
 
1744
  unordered_map<string, VAR*>::iterator iter=
1754
1745
    var_hash.find(var_name);
1755
1746
  if (iter != var_hash.end())
1756
1747
    return (*iter).second;
2156
2147
 
2157
2148
  if (!internal::test_if_hard_path(name))
2158
2149
  {
2159
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
 
2150
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir,name);
2160
2151
    name=buff;
2161
2152
  }
2162
2153
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2210
2201
    ; /* Do nothing */
2211
2202
  else
2212
2203
  {
2213
 
    if (! opt_testdir.empty())
 
2204
    if (opt_testdir != NULL)
2214
2205
    {
2215
2206
      string testdir(opt_testdir);
2216
2207
      if (testdir[testdir.length()] != '/')
3317
3308
  bool error= false;
3318
3309
  char *p= command->first_argument;
3319
3310
  char *sleep_start, *sleep_end= command->end;
3320
 
  double sleep_val= 0;
 
3311
  double sleep_val;
3321
3312
 
3322
3313
  while (my_isspace(charset_info, *p))
3323
3314
    p++;
3357
3348
  if (*p)
3358
3349
    *p++= 0;
3359
3350
  command->last_argument= p;
3360
 
  if (! opt_testdir.empty())
 
3351
  if (opt_testdir != NULL)
3361
3352
  {
3362
3353
    dest= opt_testdir;
3363
3354
    if (dest[dest.length()] != '/')
3386
3377
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3387
3378
}
3388
3379
 
3389
 
static void fill_global_error_names()
3390
 
{
3391
 
  drizzle_result_st res;
3392
 
  drizzle_return_t ret;
3393
 
  drizzle_row_t row;
3394
 
  drizzle_con_st *con= &cur_con->con;
3395
 
 
3396
 
  global_error_names.clear();
3397
 
 
3398
 
  const std::string ds_query("select error_name, error_code "
3399
 
                             "from data_dictionary.errors");
3400
 
  if (drizzle_query_str(con, &res, ds_query.c_str(), &ret) == NULL ||
3401
 
      ret != DRIZZLE_RETURN_OK)
3402
 
  {
3403
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3404
 
    {
3405
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
3406
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
3407
 
      drizzle_result_free(&res);
3408
 
    }
3409
 
    else
3410
 
    {
3411
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3412
 
          drizzle_con_error(con));
3413
 
    }
3414
 
  }
3415
 
  if (drizzle_result_column_count(&res) == 0 ||
3416
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3417
 
  {
3418
 
    drizzle_result_free(&res);
3419
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
3420
 
  }
3421
 
 
3422
 
  while ((row= drizzle_row_next(&res)) && row[0])
3423
 
  {
3424
 
    /*
3425
 
      Concatenate all fields in the first row with tab in between
3426
 
      and assign that string to the $variable
3427
 
    */
3428
 
    size_t *lengths= drizzle_row_field_sizes(&res);
3429
 
    const std::string error_name(row[0], lengths[0]);
3430
 
    const std::string error_code(row[1], lengths[1]);
3431
 
 
3432
 
    try
3433
 
    {
3434
 
      global_error_names.insert(ErrorCodes::value_type(error_name,
3435
 
                                                       boost::lexical_cast<uint32_t>(error_code)));
3436
 
    }
3437
 
    catch (boost::bad_lexical_cast &ex)
3438
 
    {
3439
 
      drizzle_result_free(&res);
3440
 
      die("Invalid error_code from Drizzle: %s", ex.what());
3441
 
    }
3442
 
 
3443
 
  }
3444
 
 
3445
 
  drizzle_result_free(&res);
3446
 
}
3447
 
 
3448
3380
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3449
3381
{
3450
3382
  size_t err_name_len= error_end - error_name;
3451
3383
  string error_name_s(error_name, err_name_len);
3452
3384
 
3453
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3454
 
  if (it != global_error_names.end())
3455
 
  {
3456
 
    return (*it).second;
3457
 
  }
3458
 
 
3459
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3460
 
  return 0;
 
3385
  uint32_t code= global_error_names.getErrorCode(error_name_s);
 
3386
 
 
3387
  if (!code)
 
3388
    die("Unknown SQL error name '%s'", error_name_s.c_str());
 
3389
 
 
3390
  return(code);
3461
3391
}
3462
3392
 
3463
3393
static void do_get_errcodes(struct st_command *command)
3755
3685
*/
3756
3686
 
3757
3687
static void safe_connect(drizzle_con_st *con, const char *name,
3758
 
                         const string host, const string user, const char *pass,
3759
 
                         const string db, uint32_t port)
 
3688
                         const char *host, const char *user, const char *pass,
 
3689
                         const char *db, int port)
3760
3690
{
3761
 
  uint32_t failed_attempts= 0;
 
3691
  int failed_attempts= 0;
3762
3692
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
3763
3693
  drizzle_return_t ret;
3764
3694
 
3765
 
  drizzle_con_set_tcp(con, host.c_str(), port);
3766
 
  drizzle_con_set_auth(con, user.c_str(), pass);
3767
 
  drizzle_con_set_db(con, db.c_str());
 
3695
  drizzle_con_set_tcp(con, host, port);
 
3696
  drizzle_con_set_auth(con, user, pass);
 
3697
  drizzle_con_set_db(con, db);
3768
3698
  while((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
3769
3699
  {
3770
3700
    /*
3906
3836
 
3907
3837
static void do_connect(struct st_command *command)
3908
3838
{
3909
 
  uint32_t con_port= opt_port;
 
3839
  int con_port= opt_port;
3910
3840
  const char *con_options;
3911
 
  bool con_ssl= 0;
 
3841
  bool con_ssl= 0, con_compress= 0;
3912
3842
  struct st_connection* con_slot;
3913
3843
 
3914
3844
  string ds_connection_name;
3974
3904
      end++;
3975
3905
    if (!strncmp(con_options, "SSL", 3))
3976
3906
      con_ssl= 1;
 
3907
    else if (!strncmp(con_options, "COMPRESS", 8))
 
3908
      con_compress= 1;
3977
3909
    else
3978
3910
      die("Illegal option to connect: %.*s",
3979
3911
          (int) (end - con_options), con_options);
3999
3931
    die("Failed on drizzle_create()");
4000
3932
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
4001
3933
    die("Failed on drizzle_con_create()");
4002
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
3934
  if (opt_mysql)
 
3935
    drizzle_con_add_options(&con_slot->con, DRIZZLE_CON_MYSQL);
4003
3936
 
4004
3937
  /* Use default db name */
4005
3938
  if (ds_database.length() == 0)
4563
4496
  return;
4564
4497
}
4565
4498
 
 
4499
 
 
4500
 
4566
4501
/*
4567
4502
  Create a command from a set of lines
4568
4503
 
4580
4515
  terminated by new line '\n' regardless how many "delimiter" it contain.
4581
4516
*/
4582
4517
 
4583
 
#define MAX_QUERY (768*1024*2) /* 256K -- a test in sp-big is >128K */
 
4518
#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */
4584
4519
static char read_command_buf[MAX_QUERY];
4585
4520
 
4586
4521
static int read_command(struct st_command** command_ptr)
4642
4577
  return(0);
4643
4578
}
4644
4579
 
 
4580
 
 
4581
static struct option my_long_options[] =
 
4582
{
 
4583
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
4584
   0, 0, 0, 0, 0, 0},
 
4585
  {"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
 
4586
   (char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4587
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
4588
   "Directory where character sets are.", (char**) &opt_charsets_dir,
 
4589
   (char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4590
  {"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
 
4591
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4592
  {"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
 
4593
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4594
  {"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
 
4595
   (char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4596
  {"testdir", OPT_TESTDIR, "Path to use to search for test files",
 
4597
   (char**) &opt_testdir,
 
4598
   (char**) &opt_testdir, 0,GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4599
  {"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
 
4600
   (char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4601
  {"mark-progress", OPT_MARK_PROGRESS,
 
4602
   "Write linenumber and elapsed time to <testname>.progress ",
 
4603
   (char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
 
4604
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4605
  {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
 
4606
   "Max number of connection attempts when connecting to server",
 
4607
   (char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
 
4608
   GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
 
4609
  {"mysql", 'm', N_("Use MySQL Protocol."),
 
4610
   (char**) &opt_mysql, (char**) &opt_mysql, 0, GET_BOOL, NO_ARG, 1, 0, 0,
 
4611
   0, 0, 0},
 
4612
  {"password", 'P', "Password to use when connecting to server.",
 
4613
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
4614
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
 
4615
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
4616
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
4617
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4618
  {"quiet", 's', "Suppress all normal output.", (char**) &silent,
 
4619
   (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4620
  {"record", 'r', "Record output of test_file into result file.",
 
4621
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4622
  {"result-file", 'R', "Read/Store result from/in this file.",
 
4623
   (char**) &result_file_name, (char**) &result_file_name, 0,
 
4624
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4625
  {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
 
4626
   (char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4627
  {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
 
4628
   (char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
 
4629
   0, 0, 0},
 
4630
  {"tail-lines", OPT_TAIL_LINES,
 
4631
   "Number of lines of the resul to include in a failure report",
 
4632
   (char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
 
4633
   GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
 
4634
  {"test-file", 'x', "Read test from/in this file (default stdin).",
 
4635
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4636
  {"timer-file", 'm', "File where the timing in micro seconds is stored.",
 
4637
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4638
  {"tmpdir", 't', "Temporary directory where sockets are put.",
 
4639
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4640
  {"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
 
4641
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4642
  {"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
 
4643
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4644
  {"version", 'V', "Output version information and exit.",
 
4645
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4646
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
4647
};
 
4648
 
 
4649
 
 
4650
static void print_version(void)
 
4651
{
 
4652
  printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
 
4653
         drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
 
4654
}
 
4655
 
 
4656
static void usage(void)
 
4657
{
 
4658
  print_version();
 
4659
  printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
 
4660
  printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
 
4661
  printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
 
4662
  printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
 
4663
  printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
 
4664
  my_print_help(my_long_options);
 
4665
  printf("  --no-defaults       Don't read default options from any options file.\n");
 
4666
  my_print_variables(my_long_options);
 
4667
}
 
4668
 
 
4669
int get_one_option(int optid, const struct option *, char *argument)
 
4670
{
 
4671
  char *endchar= NULL;
 
4672
  uint64_t temp_drizzle_port= 0;
 
4673
 
 
4674
  switch(optid) {
 
4675
  case 'r':
 
4676
    record = 1;
 
4677
    break;
 
4678
  case 'x':
 
4679
  {
 
4680
    char buff[FN_REFLEN];
 
4681
    if (!internal::test_if_hard_path(argument))
 
4682
    {
 
4683
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir,argument);
 
4684
      argument= buff;
 
4685
    }
 
4686
    internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4687
    assert(cur_file == file_stack && cur_file->file == 0);
 
4688
    if (!(cur_file->file= fopen(buff, "r")))
 
4689
    {
 
4690
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
 
4691
      return EXIT_ARGUMENT_INVALID;
 
4692
    }
 
4693
    if (!(cur_file->file_name= strdup(buff)))
 
4694
    {
 
4695
      fprintf(stderr, _("Out of memory"));
 
4696
      return EXIT_OUT_OF_MEMORY;
 
4697
    }
 
4698
    cur_file->lineno= 1;
 
4699
    break;
 
4700
  }
 
4701
  case 'm':
 
4702
  {
 
4703
    static char buff[FN_REFLEN];
 
4704
    if (!internal::test_if_hard_path(argument))
 
4705
    {
 
4706
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir,argument);
 
4707
      argument= buff;
 
4708
    }
 
4709
    internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4710
    timer_file= buff;
 
4711
    unlink(timer_file);       /* Ignore error, may not exist */
 
4712
    break;
 
4713
  }
 
4714
  case 'p':
 
4715
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
4716
    /* if there is an alpha character this is not a valid port */
 
4717
    if (strlen(endchar) != 0)
 
4718
    {
 
4719
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
4720
      return EXIT_ARGUMENT_INVALID;
 
4721
    }
 
4722
    /* If the port number is > 65535 it is not a valid port
 
4723
       This also helps with potential data loss casting unsigned long to a
 
4724
       uint32_t. */
 
4725
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
4726
    {
 
4727
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
4728
      return EXIT_ARGUMENT_INVALID;
 
4729
    }
 
4730
    else
 
4731
    {
 
4732
      opt_port= (uint32_t) temp_drizzle_port;
 
4733
    }
 
4734
    break;
 
4735
  case 'P':
 
4736
    if (argument)
 
4737
    {
 
4738
      if (opt_pass)
 
4739
        free(opt_pass);
 
4740
      opt_pass = strdup(argument);
 
4741
      if (opt_pass == NULL)
 
4742
      {
 
4743
        fprintf(stderr, _("Out of memory"));
 
4744
        return EXIT_OUT_OF_MEMORY;
 
4745
      }
 
4746
      while (*argument)
 
4747
      {
 
4748
        /* Overwriting password with 'x' */
 
4749
        *argument++= 'x';
 
4750
      }
 
4751
      tty_password= 0;
 
4752
    }
 
4753
    else
 
4754
      tty_password= 1;
 
4755
    break;
 
4756
  case 't':
 
4757
    strncpy(TMPDIR, argument, sizeof(TMPDIR));
 
4758
    break;
 
4759
  case 'V':
 
4760
    print_version();
 
4761
    exit(0);
 
4762
  case '?':
 
4763
    usage();
 
4764
    exit(0);
 
4765
  }
 
4766
  return 0;
 
4767
}
 
4768
 
 
4769
 
 
4770
static int parse_args(int argc, char **argv)
 
4771
{
 
4772
  internal::load_defaults("drizzle",load_default_groups,&argc,&argv);
 
4773
  default_argv= argv;
 
4774
 
 
4775
  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
 
4776
    exit(1);
 
4777
 
 
4778
  if (argc > 1)
 
4779
  {
 
4780
    usage();
 
4781
    exit(1);
 
4782
  }
 
4783
  if (argc == 1)
 
4784
    opt_db= *argv;
 
4785
  if (tty_password)
 
4786
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
 
4787
 
 
4788
  return 0;
 
4789
}
 
4790
 
4645
4791
/*
4646
4792
  Write the content of str into file
4647
4793
 
4660
4806
  int flags= O_WRONLY | O_CREAT;
4661
4807
  if (!internal::test_if_hard_path(fname))
4662
4808
  {
4663
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
 
4809
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir,fname);
4664
4810
    fname= buff;
4665
4811
  }
4666
4812
  internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4696
4842
void dump_result_to_log_file(const char *buf, int size)
4697
4843
{
4698
4844
  char log_file[FN_REFLEN];
4699
 
  str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(), ".log",
4700
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4845
  str_to_file(internal::fn_format(log_file, result_file_name, opt_logdir, ".log",
 
4846
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4701
4847
                        MY_REPLACE_EXT),
4702
4848
              buf, size);
4703
4849
  fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
4707
4853
void dump_progress(void)
4708
4854
{
4709
4855
  char progress_file[FN_REFLEN];
4710
 
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4711
 
                        opt_logdir.c_str(), ".progress",
4712
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4856
  str_to_file(internal::fn_format(progress_file, result_file_name,
 
4857
                        opt_logdir, ".progress",
 
4858
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4713
4859
                        MY_REPLACE_EXT),
4714
4860
              ds_progress.c_str(), ds_progress.length());
4715
4861
}
4718
4864
{
4719
4865
  char warn_file[FN_REFLEN];
4720
4866
 
4721
 
  str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(), ".warnings",
4722
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4867
  str_to_file(internal::fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
 
4868
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4723
4869
                        MY_REPLACE_EXT),
4724
4870
              ds_warning_messages.c_str(), ds_warning_messages.length());
4725
4871
}
5417
5563
 
5418
5564
}
5419
5565
 
5420
 
static void check_retries(uint32_t in_opt_max_connect_retries)
5421
 
{
5422
 
  if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5423
 
  {
5424
 
    cout << N_("Error: Invalid Value for opt_max_connect_retries"); 
5425
 
    exit(-1);
5426
 
  }
5427
 
  opt_max_connect_retries= in_opt_max_connect_retries;
5428
 
}
5429
 
 
5430
 
static void check_tail_lines(uint32_t in_opt_tail_lines)
5431
 
{
5432
 
  if (in_opt_tail_lines > 10000)
5433
 
  {
5434
 
    cout << N_("Error: Invalid Value for opt_tail_lines"); 
5435
 
    exit(-1);
5436
 
  }
5437
 
  opt_tail_lines= in_opt_tail_lines;
5438
 
}
5439
 
 
5440
 
static void check_sleep(int32_t in_opt_sleep)
5441
 
{
5442
 
  if (in_opt_sleep < -1)
5443
 
  {
5444
 
    cout << N_("Error: Invalid Value for opt_sleep"); 
5445
 
    exit(-1);
5446
 
  }
5447
 
  opt_sleep= in_opt_sleep;
5448
 
}
5449
5566
 
5450
5567
int main(int argc, char **argv)
5451
5568
{
5452
 
try
5453
 
{
5454
5569
  struct st_command *command;
5455
5570
  bool q_send_flag= 0, abort_flag= 0;
5456
5571
  uint32_t command_executed= 0, last_command_executed= 0;
5457
5572
  string save_file("");
5458
5573
  struct stat res_info;
 
5574
  MY_INIT(argv[0]);
5459
5575
 
5460
5576
  TMPDIR[0]= 0;
5461
5577
 
5462
 
  internal::my_init();
5463
 
 
5464
 
  po::options_description commandline_options("Options used only in command line");
5465
 
  commandline_options.add_options()
5466
 
  ("help,?", "Display this help and exit.")
5467
 
  ("mark-progress", po::value<bool>(&opt_mark_progress)->default_value(false)->zero_tokens(),
5468
 
  "Write linenumber and elapsed time to <testname>.progress ")
5469
 
  ("sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
5470
 
  "Sleep always this many seconds on sleep commands.")
5471
 
  ("test-file,x", po::value<string>(),
5472
 
  "Read test from/in this file (default stdin).")
5473
 
  ("timer-file,f", po::value<string>(),
5474
 
  "File where the timing in micro seconds is stored.")
5475
 
  ("tmpdir,t", po::value<string>(),
5476
 
  "Temporary directory where sockets are put.")
5477
 
  ("verbose,v", po::value<bool>(&verbose)->default_value(false),
5478
 
  "Write more.")
5479
 
  ("version,V", "Output version information and exit.")
5480
 
  ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
5481
 
  "Configuration file defaults are not used if no-defaults is set")
5482
 
  ;
5483
 
 
5484
 
  po::options_description test_options("Options specific to the drizzleimport");
5485
 
  test_options.add_options()
5486
 
  ("basedir,b", po::value<string>(&opt_basedir)->default_value(""),
5487
 
  "Basedir for tests.")
5488
 
  ("character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(""),
5489
 
  "Directory where character sets are.")
5490
 
  ("database,D", po::value<string>(&opt_db)->default_value(""),
5491
 
  "Database to use.")
5492
 
  ("include,i", po::value<string>(&opt_include)->default_value(""),
5493
 
  "Include SQL before each test case.")  
5494
 
  ("testdir", po::value<string>(&opt_testdir)->default_value(""),
5495
 
  "Path to use to search for test files")
5496
 
  ("logdir", po::value<string>(&opt_logdir)->default_value(""),
5497
 
  "Directory for log files")
5498
 
  ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
5499
 
  "Max number of connection attempts when connecting to server")
5500
 
  ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5501
 
  "Suppress all normal output.")
5502
 
  ("record,r", "Record output of test_file into result file.")
5503
 
  ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
5504
 
  "Read/Store result from/in this file.")
5505
 
  ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5506
 
  "Suppress all normal output. Synonym for --quiet.")
5507
 
  ("tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
5508
 
  "Number of lines of the resul to include in a failure report")
5509
 
  ;
5510
 
 
5511
 
  po::options_description client_options("Options specific to the client");
5512
 
  client_options.add_options()
5513
 
 
5514
 
  ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
5515
 
  "Connect to host.")
5516
 
  ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
5517
 
  "Password to use when connecting to server.")
5518
 
  ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
5519
 
  "Port number to use for connection or 0 for default")
5520
 
  ("protocol", po::value<string>(&opt_protocol),
5521
 
  "The protocol of connection (mysql or drizzle).")
5522
 
  ("user,u", po::value<string>(&opt_user)->default_value(""),
5523
 
  "User for login.")
5524
 
  ;
5525
 
 
5526
 
  po::positional_options_description p;
5527
 
  p.add("database", 1);
5528
 
 
5529
 
  po::options_description long_options("Allowed Options");
5530
 
  long_options.add(commandline_options).add(test_options).add(client_options);
5531
 
 
5532
 
  std::string system_config_dir_test(SYSCONFDIR); 
5533
 
  system_config_dir_test.append("/drizzle/drizzletest.cnf");
5534
 
 
5535
 
  std::string system_config_dir_client(SYSCONFDIR); 
5536
 
  system_config_dir_client.append("/drizzle/client.cnf");
5537
 
 
5538
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5539
 
 
5540
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
5541
 
  {
5542
 
    char *homedir;
5543
 
    homedir= getenv("HOME");
5544
 
    if (homedir != NULL)
5545
 
      user_config_dir.replace(0, 1, homedir);
5546
 
  }
5547
 
 
5548
 
  po::variables_map vm;
5549
 
 
5550
 
  // Disable allow_guessing
5551
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5552
 
 
5553
 
  po::store(po::command_line_parser(argc, argv).options(long_options).
5554
 
            style(style).positional(p).extra_parser(parse_password_arg).run(),
5555
 
            vm);
5556
 
 
5557
 
  if (! vm["no-defaults"].as<bool>())
5558
 
  {
5559
 
    std::string user_config_dir_test(user_config_dir);
5560
 
    user_config_dir_test.append("/drizzle/drizzletest.cnf"); 
5561
 
 
5562
 
    std::string user_config_dir_client(user_config_dir);
5563
 
    user_config_dir_client.append("/drizzle/client.cnf");
5564
 
 
5565
 
    ifstream user_test_ifs(user_config_dir_test.c_str());
5566
 
    po::store(parse_config_file(user_test_ifs, test_options), vm);
5567
 
 
5568
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
5569
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
5570
 
 
5571
 
    ifstream system_test_ifs(system_config_dir_test.c_str());
5572
 
    store(parse_config_file(system_test_ifs, test_options), vm);
5573
 
 
5574
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
5575
 
    po::store(parse_config_file(system_client_ifs, client_options), vm);
5576
 
  }
5577
 
 
5578
 
  po::notify(vm);
5579
 
 
5580
5578
  /* Init expected errors */
5581
5579
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5582
5580
 
5613
5611
  ds_progress.reserve(2048);
5614
5612
  ds_warning_messages.reserve(2048);
5615
5613
 
5616
 
 
5617
 
  if (vm.count("record"))
5618
 
  {
5619
 
    record = 1;
5620
 
  }
5621
 
 
5622
 
  if (vm.count("test-file"))
5623
 
  {
5624
 
    string tmp= vm["test-file"].as<string>();
5625
 
    char buff[FN_REFLEN];
5626
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5627
 
    {
5628
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5629
 
      tmp= buff;
5630
 
    }
5631
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5632
 
    assert(cur_file == file_stack && cur_file->file == 0);
5633
 
    if (!(cur_file->file= fopen(buff, "r")))
5634
 
    {
5635
 
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5636
 
      return EXIT_ARGUMENT_INVALID;
5637
 
    }
5638
 
    if (!(cur_file->file_name= strdup(buff)))
5639
 
    {
5640
 
      fprintf(stderr, _("Out of memory"));
5641
 
      return EXIT_OUT_OF_MEMORY;
5642
 
    }
5643
 
    cur_file->lineno= 1;
5644
 
  }
5645
 
 
5646
 
  if (vm.count("timer-file"))
5647
 
  {
5648
 
    string tmp= vm["timer-file"].as<string>().c_str();
5649
 
    static char buff[FN_REFLEN];
5650
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5651
 
    {
5652
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5653
 
      tmp= buff;
5654
 
    }
5655
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5656
 
    timer_file= buff;
5657
 
    unlink(timer_file);       /* Ignore error, may not exist */
5658
 
  }
5659
 
 
5660
 
  if (vm.count("protocol"))
5661
 
  {
5662
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
5663
 
      opt_protocol.begin(), ::tolower);
5664
 
 
5665
 
    if (not opt_protocol.compare("mysql"))
5666
 
      use_drizzle_protocol=false;
5667
 
    else if (not opt_protocol.compare("drizzle"))
5668
 
      use_drizzle_protocol=true;
5669
 
    else
5670
 
    {
5671
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5672
 
      exit(-1);
5673
 
    }
5674
 
  }
5675
 
 
5676
 
  if (vm.count("port"))
5677
 
  {
5678
 
    /* If the port number is > 65535 it is not a valid port
5679
 
       This also helps with potential data loss casting unsigned long to a
5680
 
       uint32_t. */
5681
 
    if (opt_port > 65535)
5682
 
    {
5683
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
5684
 
      exit(EXIT_ARGUMENT_INVALID);
5685
 
    }
5686
 
  }
5687
 
 
5688
 
  if( vm.count("password") )
5689
 
  {
5690
 
    if (!opt_password.empty())
5691
 
      opt_password.erase();
5692
 
    if (password == PASSWORD_SENTINEL)
5693
 
    {
5694
 
      opt_password= "";
5695
 
    }
5696
 
    else
5697
 
    {
5698
 
      opt_password= password;
5699
 
      tty_password= false;
5700
 
    }
5701
 
  }
5702
 
  else
5703
 
  {
5704
 
      tty_password= true;
5705
 
  }
5706
 
 
5707
 
  if (vm.count("tmpdir"))
5708
 
  {
5709
 
    strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
5710
 
  }
5711
 
 
5712
 
  if (vm.count("version"))
5713
 
  {
5714
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5715
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5716
 
    exit(0);
5717
 
  }
5718
 
  
5719
 
  if (vm.count("help"))
5720
 
  {
5721
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5722
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5723
 
    printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
5724
 
    printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5725
 
    printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
5726
 
    printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5727
 
    printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5728
 
    exit(0);
5729
 
  }
5730
 
 
5731
 
  if (tty_password)
5732
 
  {
5733
 
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
5734
 
  }
 
5614
  parse_args(argc, argv);
5735
5615
 
5736
5616
  server_initialized= 1;
5737
5617
  if (cur_file == file_stack && cur_file->file == 0)
5747
5627
    die("Failed in drizzle_create()");
5748
5628
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5749
5629
    die("Failed in drizzle_con_create()");
5750
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
5630
  if (opt_mysql)
 
5631
    drizzle_con_add_options(&cur_con->con, DRIZZLE_CON_MYSQL);
5751
5632
 
5752
5633
  if (!(cur_con->name = strdup("default")))
5753
5634
    die("Out of memory");
 
5635
 
5754
5636
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5755
5637
               opt_db, opt_port);
5756
5638
 
5757
 
  fill_global_error_names();
5758
 
 
5759
5639
  /* Use all time until exit if no explicit 'start_timer' */
5760
5640
  timer_start= timer_now();
5761
5641
 
5769
5649
  /* Update $drizzleclient_get_server_version to that of current connection */
5770
5650
  var_set_drizzleclient_get_server_version(&cur_con->con);
5771
5651
 
5772
 
  if (! opt_include.empty())
 
5652
  if (opt_include)
5773
5653
  {
5774
 
    open_file(opt_include.c_str());
 
5654
    open_file(opt_include);
5775
5655
  }
5776
5656
 
5777
5657
  while (!read_command(&command) && !abort_flag)
6075
5955
  */
6076
5956
  if (ds_res.length())
6077
5957
  {
6078
 
    if (! result_file_name.empty())
 
5958
    if (result_file_name)
6079
5959
    {
6080
5960
      /* A result file has been specified */
6081
5961
 
6082
5962
      if (record)
6083
5963
      {
6084
5964
        /* Recording - dump the output from test to result file */
6085
 
        str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
 
5965
        str_to_file(result_file_name, ds_res.c_str(), ds_res.length());
6086
5966
      }
6087
5967
      else
6088
5968
      {
6105
5985
  }
6106
5986
 
6107
5987
  if (!command_executed &&
6108
 
      ! result_file_name.empty() && !stat(result_file_name.c_str(), &res_info))
 
5988
      result_file_name && !stat(result_file_name, &res_info))
6109
5989
  {
6110
5990
    /*
6111
5991
      my_stat() successful on result file. Check if we have not run a
6117
5997
    die("No queries executed but result file found!");
6118
5998
  }
6119
5999
 
6120
 
  if ( opt_mark_progress && ! result_file_name.empty() )
 
6000
  if ( opt_mark_progress && result_file_name )
6121
6001
    dump_progress();
6122
6002
 
6123
6003
  /* Dump warning messages */
6124
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
6004
  if (result_file_name && ds_warning_messages.length())
6125
6005
    dump_warning_messages();
6126
6006
 
6127
6007
  timer_output();
6128
6008
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
6129
6009
  cleanup_and_exit(0);
6130
 
}
6131
 
 
6132
 
  catch(exception &err)
6133
 
  {
6134
 
    cerr<<err.what()<<endl;
6135
 
  }
6136
 
 
6137
6010
  return 0; /* Keep compiler happy too */
6138
6011
}
6139
6012
 
6716
6589
    /* Repeatedly replace the string with the matched regex */
6717
6590
    string subject(in_string);
6718
6591
    size_t replace_length= strlen(replace);
6719
 
    size_t length_of_replacement= strlen(replace);
6720
6592
    size_t current_position= 0;
6721
6593
    int rc= 0;
6722
 
 
6723
 
    while (true) 
 
6594
    while(0 >= (rc= pcre_exec(re, NULL, subject.c_str() + current_position, subject.length() - current_position,
 
6595
                      0, 0, ovector, 3)))
6724
6596
    {
6725
 
      rc= pcre_exec(re, NULL, subject.c_str(), subject.length(), 
6726
 
                    current_position, 0, ovector, 3);
6727
 
      if (rc < 0)
6728
 
      {
6729
 
        break;
6730
 
      }
6731
 
 
6732
6597
      current_position= static_cast<size_t>(ovector[0]);
6733
6598
      replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6734
 
      subject.replace(current_position, replace_length, replace, length_of_replacement);
6735
 
      current_position= current_position + length_of_replacement;
 
6599
      subject.replace(current_position, replace_length, replace, replace_length);
6736
6600
    }
6737
6601
 
6738
6602
    char *new_buf = (char *) malloc(subject.length() + 1);