~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

Reverted 1103

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>
52
50
#ifdef HAVE_SYS_WAIT_H
53
51
#include <sys/wait.h>
54
52
#endif
55
 
#include <cassert>
56
 
#include <sys/stat.h>
57
 
#include <sys/types.h>
58
 
#include <fcntl.h>
59
 
#include <boost/program_options.hpp>
60
53
 
61
54
#include PCRE_HEADER
62
55
 
 
56
#include <mysys/hash.h>
63
57
#include <stdarg.h>
64
 
#include <boost/unordered_map.hpp>
 
58
 
 
59
#include "errname.h"
65
60
 
66
61
/* Added this for string translation. */
67
 
#include "drizzled/gettext.h"
68
 
#include "drizzled/type/time.h"
69
 
#include "drizzled/charset.h"
70
 
#include "drizzled/typelib.h"
71
 
#include <drizzled/configmake.h>
 
62
#include <drizzled/gettext.h>
72
63
 
73
64
#ifndef DRIZZLE_RETURN_SERVER_GONE
74
65
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
75
66
#endif
76
 
namespace po= boost::program_options;
 
67
 
77
68
using namespace std;
78
 
using namespace drizzled;
79
69
 
80
70
extern "C"
81
 
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
82
 
 
83
 
int get_one_option(int optid, const struct option *, char *argument);
 
71
{
 
72
  unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
 
73
  bool get_one_option(int optid, const struct my_option *, char *argument);
 
74
}
84
75
 
85
76
#define MAX_VAR_NAME_LENGTH    256
86
77
#define MAX_COLUMNS            256
 
78
#define MAX_EMBEDDED_SERVER_ARGS 64
87
79
#define MAX_DELIMITER_LENGTH 16
88
80
/* Flags controlling send and reap */
89
81
#define QUERY_SEND_FLAG  1
90
82
#define QUERY_REAP_FLAG  2
91
83
 
92
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
93
 
ErrorCodes global_error_names;
94
 
 
95
84
enum {
96
85
  OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
97
86
  OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
99
88
};
100
89
 
101
90
static int record= 0, opt_sleep= -1;
102
 
static char *opt_pass= NULL;
103
 
const char *unix_sock= NULL;
 
91
static char *opt_db= NULL, *opt_pass= NULL;
 
92
const char *opt_user= NULL, *opt_host= NULL, *unix_sock= NULL,
 
93
           *opt_basedir= "./";
 
94
const char *opt_logdir= "";
 
95
const char *opt_include= NULL, *opt_charsets_dir;
 
96
const char *opt_testdir= NULL;
104
97
static uint32_t opt_port= 0;
105
 
static uint32_t opt_max_connect_retries;
106
 
static bool silent= false, verbose= false;
 
98
static int opt_max_connect_retries;
 
99
static bool opt_compress= false, silent= false, verbose= false;
 
100
static bool debug_info_flag= false, debug_check_flag= false;
 
101
static bool tty_password= false;
107
102
static bool opt_mark_progress= false;
108
103
static bool parsing_disabled= false;
109
104
static bool display_result_vertically= false,
114
109
static bool abort_on_error= true;
115
110
static bool server_initialized= false;
116
111
static bool is_windows= false;
117
 
static bool use_drizzle_protocol= false;
 
112
static char **default_argv;
 
113
static const char *load_default_groups[]= { "drizzletest", "client", 0 };
118
114
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
119
115
 
120
 
std::string opt_basedir,
121
 
  opt_charsets_dir,
122
 
  opt_db,
123
 
  opt_host,
124
 
  opt_include,
125
 
  opt_testdir,
126
 
  opt_logdir,
127
 
  password,
128
 
  opt_password,
129
 
  result_file_name,
130
 
  opt_user,
131
 
  opt_protocol;
132
 
 
133
116
static uint32_t start_lineno= 0; /* Start line of current command */
 
117
static uint32_t my_end_arg= 0;
134
118
 
135
119
/* Number of lines of the result to include in failure report */
136
120
static uint32_t opt_tail_lines= 0;
172
156
 
173
157
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
174
158
 
 
159
static int embedded_server_arg_count=0;
 
160
static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS];
 
161
 
175
162
/*
176
163
  Timer related variables
177
164
  See the timer_output() definition for details
199
186
master_pos_st master_pos;
200
187
 
201
188
/* if set, all results are concated and compared against this file */
 
189
const char *result_file_name= NULL;
202
190
 
203
191
typedef struct st_var
204
192
{
216
204
/*Perl/shell-like variable registers */
217
205
VAR var_reg[10];
218
206
 
219
 
 
220
 
boost::unordered_map<string, VAR *> var_hash;
 
207
HASH var_hash;
221
208
 
222
209
struct st_connection
223
210
{
397
384
  char *query, *query_buf,*first_argument,*last_argument,*end;
398
385
  int first_word_len, query_len;
399
386
  bool abort_on_error;
400
 
  st_expected_errors expected_errors;
401
 
  string require_file;
 
387
  struct st_expected_errors expected_errors;
 
388
  char require_file[FN_REFLEN];
402
389
  enum enum_commands type;
403
 
 
404
 
  st_command()
405
 
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
406
 
      end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
407
 
      require_file(""), type(Q_CONNECTION)
408
 
  {
409
 
    memset(&expected_errors, 0, sizeof(st_expected_errors));
410
 
  }
411
 
 
412
 
  ~st_command()
413
 
  {
414
 
    if (query_buf != NULL)
415
 
    {
416
 
      free(query_buf);
417
 
    }
418
 
  }
419
390
};
420
391
 
421
392
TYPELIB command_typelib= {array_elements(command_names),"",
439
410
VAR* var_from_env(const char *, const char *);
440
411
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
441
412
              int val_len);
442
 
void var_free(pair<string, VAR*> v);
 
413
extern "C" void var_free(void* v);
443
414
VAR* var_get(const char *var_name, const char** var_name_end,
444
415
             bool raw, bool ignore_not_existing);
445
416
void eval_expr(VAR* v, const char *p, const char** p_end);
783
754
    const struct command_arg *arg= &args[i];
784
755
    arg->ds->clear();
785
756
 
786
 
    bool known_arg_type= true;
787
757
    switch (arg->type) {
788
758
      /* A string */
789
759
    case ARG_STRING:
818
788
      break;
819
789
 
820
790
    default:
821
 
      known_arg_type= false;
 
791
      assert("Unknown argument type");
822
792
      break;
823
793
    }
824
 
    assert(known_arg_type);
825
794
 
826
795
    /* Check required arg */
827
796
    if (arg->ds->length() == 0 && arg->required)
844
813
 
845
814
static void handle_command_error(struct st_command *command, uint32_t error)
846
815
{
 
816
 
847
817
  if (error != 0)
848
818
  {
849
819
    uint32_t i;
870
840
        command->first_word_len, command->query,
871
841
        command->expected_errors.err[0].code.errnum);
872
842
  }
 
843
  return;
873
844
}
874
845
 
875
846
 
911
882
 
912
883
  close_connections();
913
884
  close_files();
914
 
  for_each(var_hash.begin(), var_hash.end(), var_free);
915
 
  var_hash.clear();
 
885
  hash_free(&var_hash);
916
886
 
917
 
  vector<st_command *>::iterator iter;
 
887
  vector<struct st_command *>::iterator iter;
918
888
  for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
919
889
  {
920
890
    struct st_command * q_line= *iter;
921
 
    delete q_line;
 
891
    if (q_line->query_buf != NULL)
 
892
    {
 
893
      free(q_line->query_buf);
 
894
    }
 
895
    free(q_line);
922
896
  }
923
897
 
924
898
  for (i= 0; i < 10; i++)
926
900
    if (var_reg[i].alloced_len)
927
901
      free(var_reg[i].str_val);
928
902
  }
 
903
  while (embedded_server_arg_count > 1)
 
904
    free(embedded_server_args[--embedded_server_arg_count]);
929
905
 
930
906
  free_all_replace();
931
907
  free(opt_pass);
 
908
  free_defaults(default_argv);
932
909
 
933
910
  return;
934
911
}
937
914
static void cleanup_and_exit(int exit_code)
938
915
{
939
916
  free_used_memory();
940
 
  internal::my_end();
 
917
  my_end(my_end_arg);
941
918
 
942
919
  if (!silent) {
943
920
    switch (exit_code) {
1010
987
  }
1011
988
 
1012
989
  /* Dump the result that has been accumulated so far to .log file */
1013
 
  if (! result_file_name.empty() && ds_res.length())
 
990
  if (result_file_name && ds_res.length())
1014
991
    dump_result_to_log_file(ds_res.c_str(), ds_res.length());
1015
992
 
1016
993
  /* Dump warning messages */
1017
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
994
  if (result_file_name && ds_warning_messages.length())
1018
995
    dump_warning_messages();
1019
996
 
1020
997
  /*
1150
1127
  uint32_t len;
1151
1128
  char buff[512];
1152
1129
 
1153
 
  if ((fd= internal::my_open(filename, O_RDONLY, MYF(0))) < 0)
 
1130
  if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0)
1154
1131
    die("Failed to open file '%s'", filename);
1155
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1132
  while((len= my_read(fd, (unsigned char*)&buff,
1156
1133
                      sizeof(buff), MYF(0))) > 0)
1157
1134
  {
1158
1135
    char *p= buff, *start= buff;
1174
1151
    /* Output any chars that might be left */
1175
1152
    ds->append(start, p-start);
1176
1153
  }
1177
 
  internal::my_close(fd, MYF(0));
 
1154
  my_close(fd, MYF(0));
1178
1155
}
1179
1156
 
1180
1157
 
1350
1327
 
1351
1328
*/
1352
1329
 
1353
 
static int compare_files2(int fd, const char* filename2)
 
1330
static int compare_files2(File fd, const char* filename2)
1354
1331
{
1355
1332
  int error= RESULT_OK;
1356
 
  int fd2;
 
1333
  File fd2;
1357
1334
  uint32_t len, len2;
1358
1335
  char buff[512], buff2[512];
1359
1336
  const char *fname= filename2;
1360
1337
  string tmpfile;
1361
1338
 
1362
 
  if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
 
1339
  if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1363
1340
  {
1364
 
    internal::my_close(fd, MYF(0));
1365
 
    if (! opt_testdir.empty())
 
1341
    my_close(fd, MYF(0));
 
1342
    if (opt_testdir != NULL)
1366
1343
    {
1367
1344
      tmpfile= opt_testdir;
1368
1345
      if (tmpfile[tmpfile.length()] != '/')
1370
1347
      tmpfile.append(filename2);
1371
1348
      fname= tmpfile.c_str();
1372
1349
    }
1373
 
    if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
 
1350
    if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1374
1351
    {
1375
 
      internal::my_close(fd, MYF(0));
 
1352
      my_close(fd, MYF(0));
1376
1353
    
1377
1354
      die("Failed to open second file: '%s'", fname);
1378
1355
    }
1379
1356
  }
1380
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1357
  while((len= my_read(fd, (unsigned char*)&buff,
1381
1358
                      sizeof(buff), MYF(0))) > 0)
1382
1359
  {
1383
 
    if ((len2= internal::my_read(fd2, (unsigned char*)&buff2,
 
1360
    if ((len2= my_read(fd2, (unsigned char*)&buff2,
1384
1361
                       sizeof(buff2), MYF(0))) < len)
1385
1362
    {
1386
1363
      /* File 2 was smaller */
1400
1377
      break;
1401
1378
    }
1402
1379
  }
1403
 
  if (!error && internal::my_read(fd2, (unsigned char*)&buff2,
 
1380
  if (!error && my_read(fd2, (unsigned char*)&buff2,
1404
1381
                        sizeof(buff2), MYF(0)) > 0)
1405
1382
  {
1406
1383
    /* File 1 was smaller */
1407
1384
    error= RESULT_LENGTH_MISMATCH;
1408
1385
  }
1409
1386
 
1410
 
  internal::my_close(fd2, MYF(0));
 
1387
  my_close(fd2, MYF(0));
1411
1388
 
1412
1389
  return error;
1413
1390
}
1428
1405
 
1429
1406
static int compare_files(const char* filename1, const char* filename2)
1430
1407
{
1431
 
  int fd;
 
1408
  File fd;
1432
1409
  int error;
1433
1410
 
1434
 
  if ((fd= internal::my_open(filename1, O_RDONLY, MYF(0))) < 0)
 
1411
  if ((fd= my_open(filename1, O_RDONLY, MYF(0))) < 0)
1435
1412
    die("Failed to open first file: '%s'", filename1);
1436
1413
 
1437
1414
  error= compare_files2(fd, filename2);
1438
1415
 
1439
 
  internal::my_close(fd, MYF(0));
 
1416
  my_close(fd, MYF(0));
1440
1417
 
1441
1418
  return error;
1442
1419
}
1457
1434
static int string_cmp(string* ds, const char *fname)
1458
1435
{
1459
1436
  int error;
1460
 
  int fd;
 
1437
  File fd;
1461
1438
  char temp_file_path[FN_REFLEN];
1462
1439
 
1463
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
 
1440
  if ((fd= create_temp_file(temp_file_path, NULL,
1464
1441
                            "tmp", MYF(MY_WME))) < 0)
1465
1442
    die("Failed to create temporary file for ds");
1466
1443
 
1467
1444
  /* Write ds to temporary file and set file pos to beginning*/
1468
 
  if (internal::my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
 
1445
  if (my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
1469
1446
               MYF(MY_FNABP | MY_WME)) ||
1470
1447
      lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
1471
1448
  {
1472
 
    internal::my_close(fd, MYF(0));
 
1449
    my_close(fd, MYF(0));
1473
1450
    /* Remove the temporary file */
1474
 
    internal::my_delete(temp_file_path, MYF(0));
 
1451
    my_delete(temp_file_path, MYF(0));
1475
1452
    die("Failed to write file '%s'", temp_file_path);
1476
1453
  }
1477
1454
 
1478
1455
  error= compare_files2(fd, fname);
1479
1456
 
1480
 
  internal::my_close(fd, MYF(0));
 
1457
  my_close(fd, MYF(0));
1481
1458
  /* Remove the temporary file */
1482
 
  internal::my_delete(temp_file_path, MYF(0));
 
1459
  my_delete(temp_file_path, MYF(0));
1483
1460
 
1484
1461
  return(error);
1485
1462
}
1502
1479
  const char* mess= "Result content mismatch\n";
1503
1480
 
1504
1481
 
1505
 
  assert(result_file_name.c_str());
1506
 
 
1507
 
  if (access(result_file_name.c_str(), F_OK) != 0)
1508
 
    die("The specified result file does not exist: '%s'", result_file_name.c_str());
1509
 
 
1510
 
  switch (string_cmp(ds, result_file_name.c_str())) {
 
1482
  assert(result_file_name);
 
1483
 
 
1484
  if (access(result_file_name, F_OK) != 0)
 
1485
    die("The specified result file does not exist: '%s'", result_file_name);
 
1486
 
 
1487
  switch (string_cmp(ds, result_file_name)) {
1511
1488
  case RESULT_OK:
1512
1489
    break; /* ok */
1513
1490
  case RESULT_LENGTH_MISMATCH:
1521
1498
    */
1522
1499
    char reject_file[FN_REFLEN];
1523
1500
    size_t reject_length;
1524
 
    internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
 
1501
    dirname_part(reject_file, result_file_name, &reject_length);
1525
1502
 
1526
1503
    if (access(reject_file, W_OK) == 0)
1527
1504
    {
1528
1505
      /* Result file directory is writable, save reject file there */
1529
 
      internal::fn_format(reject_file, result_file_name.c_str(), NULL,
 
1506
      fn_format(reject_file, result_file_name, NULL,
1530
1507
                ".reject", MY_REPLACE_EXT);
1531
1508
    }
1532
1509
    else
1533
1510
    {
1534
1511
      /* Put reject file in opt_logdir */
1535
 
      internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
 
1512
      fn_format(reject_file, result_file_name, opt_logdir,
1536
1513
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1537
1514
    }
1538
1515
    str_to_file(reject_file, ds->c_str(), ds->length());
1539
1516
 
1540
1517
    ds->erase(); /* Don't create a .log file */
1541
1518
 
1542
 
    show_diff(NULL, result_file_name.c_str(), reject_file);
 
1519
    show_diff(NULL, result_file_name, reject_file);
1543
1520
    die("%s",mess);
1544
1521
    break;
1545
1522
  }
1566
1543
 
1567
1544
*/
1568
1545
 
1569
 
static void check_require(string* ds, const string &fname)
 
1546
static void check_require(string* ds, const char *fname)
1570
1547
{
1571
1548
 
1572
1549
 
1573
 
  if (string_cmp(ds, fname.c_str()))
 
1550
  if (string_cmp(ds, fname))
1574
1551
  {
1575
1552
    char reason[FN_REFLEN];
1576
 
    internal::fn_format(reason, fname.c_str(), "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
 
1553
    fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
1577
1554
    abort_not_supported_test("Test requires: '%s'", reason);
1578
1555
  }
1579
1556
  return;
1624
1601
}
1625
1602
 
1626
1603
 
 
1604
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool)
 
1605
{
 
1606
  register char* key;
 
1607
  key = ((VAR*)var)->name;
 
1608
  *len = ((VAR*)var)->name_len;
 
1609
  return (unsigned char*)key;
 
1610
}
 
1611
 
1627
1612
 
1628
1613
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1629
1614
              int val_len)
1661
1646
}
1662
1647
 
1663
1648
 
1664
 
void var_free(pair<string, VAR *> v)
 
1649
void var_free(void *v)
1665
1650
{
1666
 
  free(v.second->str_val);
1667
 
  free(v.second->env_s);
1668
 
  if (v.second->alloced)
1669
 
    free(v.second);
 
1651
  free(((VAR*) v)->str_val);
 
1652
  free(((VAR*) v)->env_s);
 
1653
  if (((VAR*)v)->alloced)
 
1654
    free(v);
1670
1655
}
1671
1656
 
1672
1657
 
1678
1663
    tmp = def_val;
1679
1664
 
1680
1665
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
1681
 
  string var_name(name);
1682
 
  var_hash.insert(make_pair(var_name, v));
 
1666
  my_hash_insert(&var_hash, (unsigned char*)v);
1683
1667
  return v;
1684
1668
}
1685
1669
 
1710
1694
    if (length >= MAX_VAR_NAME_LENGTH)
1711
1695
      die("Too long variable name: %s", save_var_name);
1712
1696
 
1713
 
    string save_var_name_str(save_var_name, length);
1714
 
    boost::unordered_map<string, VAR*>::iterator iter=
1715
 
      var_hash.find(save_var_name_str);
1716
 
    if (iter == var_hash.end())
 
1697
    if (!(v = (VAR*) hash_search(&var_hash, (const unsigned char*) save_var_name,
 
1698
                                 length)))
1717
1699
    {
1718
1700
      char buff[MAX_VAR_NAME_LENGTH+1];
1719
1701
      strncpy(buff, save_var_name, length);
1720
1702
      buff[length]= '\0';
1721
1703
      v= var_from_env(buff, "");
1722
1704
    }
1723
 
    else
1724
 
    {
1725
 
      v= (*iter).second;
1726
 
    }
1727
1705
    var_name--;  /* Point at last character */
1728
1706
  }
1729
1707
  else
1748
1726
 
1749
1727
static VAR *var_obtain(const char *name, int len)
1750
1728
{
1751
 
  string var_name(name, len);
1752
 
  boost::unordered_map<string, VAR*>::iterator iter=
1753
 
    var_hash.find(var_name);
1754
 
  if (iter != var_hash.end())
1755
 
    return (*iter).second;
1756
 
  VAR *v = var_init(0, name, len, "", 0);
1757
 
  var_hash.insert(make_pair(var_name, v));
 
1729
  VAR* v;
 
1730
  if ((v = (VAR*)hash_search(&var_hash, (const unsigned char *) name, len)))
 
1731
    return v;
 
1732
  v = var_init(0, name, len, "", 0);
 
1733
  my_hash_insert(&var_hash, (unsigned char*)v);
1758
1734
  return v;
1759
1735
}
1760
1736
 
2116
2092
    const size_t len= strlen(get_value_str);
2117
2093
    if (strncmp(p, get_value_str, len)==0)
2118
2094
    {
2119
 
      st_command command;
 
2095
      struct st_command command;
 
2096
      memset(&command, 0, sizeof(command));
2120
2097
      command.query= (char*)p;
2121
2098
      command.first_word_len= len;
2122
2099
      command.first_argument= command.query + len;
2153
2130
{
2154
2131
  char buff[FN_REFLEN];
2155
2132
 
2156
 
  if (!internal::test_if_hard_path(name))
 
2133
  if (!test_if_hard_path(name))
2157
2134
  {
2158
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
 
2135
    sprintf(buff,"%s%s",opt_basedir,name);
2159
2136
    name=buff;
2160
2137
  }
2161
 
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
2138
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2162
2139
 
2163
2140
  if (cur_file == file_stack_end)
2164
2141
    die("Source directives are nesting too deep");
2209
2186
    ; /* Do nothing */
2210
2187
  else
2211
2188
  {
2212
 
    if (! opt_testdir.empty())
 
2189
    if (opt_testdir != NULL)
2213
2190
    {
2214
2191
      string testdir(opt_testdir);
2215
2192
      if (testdir[testdir.length()] != '/')
2477
2454
                     rm_args, sizeof(rm_args)/sizeof(struct command_arg),
2478
2455
                     ' ');
2479
2456
 
2480
 
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
 
2457
  error= my_delete(ds_filename.c_str(), MYF(0)) != 0;
2481
2458
  handle_command_error(command, error);
 
2459
  return;
2482
2460
}
2483
2461
 
2484
2462
 
2510
2488
                     sizeof(copy_file_args)/sizeof(struct command_arg),
2511
2489
                     ' ');
2512
2490
 
2513
 
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
 
2491
  error= (my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2514
2492
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2515
2493
  handle_command_error(command, error);
 
2494
  return;
2516
2495
}
2517
2496
 
2518
2497
 
2546
2525
  /* Parse what mode to set */
2547
2526
  istringstream buff(ds_mode);
2548
2527
  if (ds_mode.length() != 4 ||
2549
 
      (buff >> oct >> mode).fail())
 
2528
      (buff >> mode).fail())
2550
2529
    die("You must write a 4 digit octal number for mode");
2551
2530
 
2552
2531
  handle_command_error(command, chmod(ds_file.c_str(), mode));
 
2532
  return;
2553
2533
}
2554
2534
 
2555
2535
 
2579
2559
 
2580
2560
  error= (access(ds_filename.c_str(), F_OK) != 0);
2581
2561
  handle_command_error(command, error);
 
2562
  return;
2582
2563
}
2583
2564
 
2584
2565
 
2605
2586
                     mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg),
2606
2587
                     ' ');
2607
2588
 
2608
 
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
 
2589
  error= mkdir(ds_dirname.c_str(), (0777 & my_umask_dir)) != 0;
2609
2590
  handle_command_error(command, error);
 
2591
  return;
2610
2592
}
2611
2593
 
2612
2594
/*
2634
2616
 
2635
2617
  error= rmdir(ds_dirname.c_str()) != 0;
2636
2618
  handle_command_error(command, error);
 
2619
  return;
2637
2620
}
2638
2621
 
2639
2622
 
2872
2855
  }
2873
2856
 
2874
2857
  handle_command_error(command, error);
 
2858
  return;
2875
2859
}
2876
2860
 
2877
2861
 
2921
2905
 
2922
2906
  if (drizzle_quit(&con->con,&result, &ret))
2923
2907
    drizzle_result_free(&result);
 
2908
 
 
2909
  return;
2924
2910
}
2925
2911
 
2926
2912
 
2967
2953
static void do_perl(struct st_command *command)
2968
2954
{
2969
2955
  int error;
2970
 
  int fd;
 
2956
  File fd;
2971
2957
  FILE *res_file;
2972
2958
  char buf[FN_REFLEN];
2973
2959
  char temp_file_path[FN_REFLEN];
2991
2977
  read_until_delimiter(&ds_script, &ds_delimiter);
2992
2978
 
2993
2979
  /* Create temporary file name */
2994
 
  if ((fd= internal::create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
 
2980
  if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
2995
2981
                            "tmp", MYF(MY_WME))) < 0)
2996
2982
    die("Failed to create temporary file for perl command");
2997
 
  internal::my_close(fd, MYF(0));
 
2983
  my_close(fd, MYF(0));
2998
2984
 
2999
2985
  str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
3000
2986
 
3014
3000
  error= pclose(res_file);
3015
3001
 
3016
3002
  /* Remove the temporary file */
3017
 
  internal::my_delete(temp_file_path, MYF(0));
 
3003
  my_delete(temp_file_path, MYF(0));
3018
3004
 
3019
3005
  handle_command_error(command, WEXITSTATUS(error));
 
3006
  return;
3020
3007
}
3021
3008
 
3022
3009
 
3119
3106
  if (!master_pos.file[0])
3120
3107
    die("Calling 'sync_with_master' without calling 'save_master_pos'");
3121
3108
 
3122
 
  snprintf(query_buf, sizeof(query_buf), "select master_pos_wait('%s', %ld)", master_pos.file,
 
3109
  sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
3123
3110
          master_pos.pos + offset);
3124
3111
 
3125
3112
wait_for_position:
3306
3293
  bool error= false;
3307
3294
  char *p= command->first_argument;
3308
3295
  char *sleep_start, *sleep_end= command->end;
3309
 
  double sleep_val= 0;
 
3296
  double sleep_val;
3310
3297
 
3311
3298
  while (my_isspace(charset_info, *p))
3312
3299
    p++;
3313
3300
  if (!*p)
3314
3301
    die("Missing argument to %.*s", command->first_word_len, command->query);
3315
3302
  sleep_start= p;
3316
 
  /* Check that arg starts with a digit, not handled by internal::my_strtod */
 
3303
  /* Check that arg starts with a digit, not handled by my_strtod */
3317
3304
  if (!my_isdigit(charset_info, *sleep_start))
3318
3305
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
3319
3306
        command->query,command->first_argument);
3335
3322
}
3336
3323
 
3337
3324
 
3338
 
static void do_get_file_name(struct st_command *command, string &dest)
 
3325
static void do_get_file_name(struct st_command *command,
 
3326
                             char* dest, uint32_t dest_max_len)
3339
3327
{
3340
3328
  char *p= command->first_argument, *name;
3341
3329
  if (!*p)
3346
3334
  if (*p)
3347
3335
    *p++= 0;
3348
3336
  command->last_argument= p;
3349
 
  if (! opt_testdir.empty())
3350
 
  {
3351
 
    dest= opt_testdir;
3352
 
    if (dest[dest.length()] != '/')
3353
 
      dest.append("/");
3354
 
  }
3355
 
  dest.append(name);
 
3337
  strncpy(dest, name, dest_max_len - 1);
3356
3338
}
3357
3339
 
3358
3340
 
3375
3357
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3376
3358
}
3377
3359
 
3378
 
static void fill_global_error_names()
3379
 
{
3380
 
  drizzle_result_st res;
3381
 
  drizzle_return_t ret;
3382
 
  drizzle_row_t row;
3383
 
  drizzle_con_st *con= &cur_con->con;
3384
 
 
3385
 
  global_error_names.clear();
3386
 
 
3387
 
  const std::string ds_query("select error_name, error_code "
3388
 
                             "from data_dictionary.errors");
3389
 
  if (drizzle_query_str(con, &res, ds_query.c_str(), &ret) == NULL ||
3390
 
      ret != DRIZZLE_RETURN_OK)
3391
 
  {
3392
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3393
 
    {
3394
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
3395
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
3396
 
      drizzle_result_free(&res);
3397
 
    }
3398
 
    else
3399
 
    {
3400
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3401
 
          drizzle_con_error(con));
3402
 
    }
3403
 
  }
3404
 
  if (drizzle_result_column_count(&res) == 0 ||
3405
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3406
 
  {
3407
 
    drizzle_result_free(&res);
3408
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
3409
 
  }
3410
 
 
3411
 
  while ((row= drizzle_row_next(&res)) && row[0])
3412
 
  {
3413
 
    /*
3414
 
      Concatenate all fields in the first row with tab in between
3415
 
      and assign that string to the $variable
3416
 
    */
3417
 
    size_t *lengths= drizzle_row_field_sizes(&res);
3418
 
    const std::string error_name(row[0], lengths[0]);
3419
 
    const std::string error_code(row[1], lengths[1]);
3420
 
 
3421
 
    try
3422
 
    {
3423
 
      global_error_names.insert(ErrorCodes::value_type(error_name,
3424
 
                                                       boost::lexical_cast<uint32_t>(error_code)));
3425
 
    }
3426
 
    catch (boost::bad_lexical_cast &ex)
3427
 
    {
3428
 
      drizzle_result_free(&res);
3429
 
      die("Invalid error_code from Drizzle: %s", ex.what());
3430
 
    }
3431
 
 
3432
 
  }
3433
 
 
3434
 
  drizzle_result_free(&res);
3435
 
}
3436
 
 
3437
3360
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3438
3361
{
3439
3362
  size_t err_name_len= error_end - error_name;
3440
3363
  string error_name_s(error_name, err_name_len);
3441
3364
 
3442
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3443
 
  if (it != global_error_names.end())
3444
 
  {
3445
 
    return (*it).second;
3446
 
  }
3447
 
 
3448
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3449
 
  return 0;
 
3365
  uint32_t code= global_error_names.getErrorCode(error_name_s);
 
3366
 
 
3367
  if (!code)
 
3368
    die("Unknown SQL error name '%s'", error_name_s.c_str());
 
3369
 
 
3370
  return(code);
3450
3371
}
3451
3372
 
3452
3373
static void do_get_errcodes(struct st_command *command)
3514
3435
    {
3515
3436
      die("The error name definition must start with an uppercase E");
3516
3437
    }
3517
 
    else if (*p == 'H')
 
3438
    else
3518
3439
    {
3519
 
      /* Error name string */
3520
 
 
3521
 
      to->code.errnum= get_errcode_from_name(p, end);
 
3440
      long val;
 
3441
      char *start= p;
 
3442
      /* Check that the string passed to str2int only contain digits */
 
3443
      while (*p && p != end)
 
3444
      {
 
3445
        if (!my_isdigit(charset_info, *p))
 
3446
          die("Invalid argument to error: '%s' - "              \
 
3447
              "the errno may only consist of digits[0-9]",
 
3448
              command->first_argument);
 
3449
        p++;
 
3450
      }
 
3451
 
 
3452
      /* Convert the sting to int */
 
3453
      istringstream buff(start);
 
3454
      if ((buff >> val).fail())
 
3455
        die("Invalid argument to error: '%s'", command->first_argument);
 
3456
 
 
3457
      to->code.errnum= (uint32_t) val;
3522
3458
      to->type= ERR_ERRNO;
3523
3459
    }
3524
 
    else
3525
 
    {
3526
 
      die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3527
 
    }
3528
3460
    to++;
3529
3461
    count++;
3530
3462
 
3733
3665
*/
3734
3666
 
3735
3667
static void safe_connect(drizzle_con_st *con, const char *name,
3736
 
                         const string host, const string user, const char *pass,
3737
 
                         const string db, uint32_t port)
 
3668
                         const char *host, const char *user, const char *pass,
 
3669
                         const char *db, int port)
3738
3670
{
3739
 
  uint32_t failed_attempts= 0;
 
3671
  int failed_attempts= 0;
3740
3672
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
3741
3673
  drizzle_return_t ret;
3742
3674
 
3743
 
  drizzle_con_set_tcp(con, host.c_str(), port);
3744
 
  drizzle_con_set_auth(con, user.c_str(), pass);
3745
 
  drizzle_con_set_db(con, db.c_str());
 
3675
  drizzle_con_set_tcp(con, host, port);
 
3676
  drizzle_con_set_auth(con, user, pass);
 
3677
  drizzle_con_set_db(con, db);
3746
3678
  while((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
3747
3679
  {
3748
3680
    /*
3884
3816
 
3885
3817
static void do_connect(struct st_command *command)
3886
3818
{
3887
 
  uint32_t con_port= opt_port;
 
3819
  int con_port= opt_port;
3888
3820
  const char *con_options;
3889
 
  bool con_ssl= 0;
 
3821
  bool con_ssl= 0, con_compress= 0;
3890
3822
  struct st_connection* con_slot;
3891
3823
 
3892
3824
  string ds_connection_name;
3932
3864
    if (*ds_sock.c_str() != FN_LIBCHAR)
3933
3865
    {
3934
3866
      char buff[FN_REFLEN];
3935
 
      internal::fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
 
3867
      fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
3936
3868
      ds_sock.clear();
3937
3869
      ds_sock.append(buff);
3938
3870
    }
3952
3884
      end++;
3953
3885
    if (!strncmp(con_options, "SSL", 3))
3954
3886
      con_ssl= 1;
 
3887
    else if (!strncmp(con_options, "COMPRESS", 8))
 
3888
      con_compress= 1;
3955
3889
    else
3956
3890
      die("Illegal option to connect: %.*s",
3957
3891
          (int) (end - con_options), con_options);
3977
3911
    die("Failed on drizzle_create()");
3978
3912
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
3979
3913
    die("Failed on drizzle_con_create()");
3980
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
3981
3914
 
3982
3915
  /* Use default db name */
3983
3916
  if (ds_database.length() == 0)
4197
4130
 
4198
4131
*/
4199
4132
 
4200
 
 
4201
 
static int my_strnncoll_simple(const CHARSET_INFO * const  cs, const unsigned char *s, size_t slen,
4202
 
                               const unsigned char *t, size_t tlen,
4203
 
                               bool t_is_prefix)
4204
 
{
4205
 
  size_t len = ( slen > tlen ) ? tlen : slen;
4206
 
  unsigned char *map= cs->sort_order;
4207
 
  if (t_is_prefix && slen > tlen)
4208
 
    slen=tlen;
4209
 
  while (len--)
4210
 
  {
4211
 
    if (map[*s++] != map[*t++])
4212
 
      return ((int) map[s[-1]] - (int) map[t[-1]]);
4213
 
  }
4214
 
  /*
4215
 
    We can't use (slen - tlen) here as the result may be outside of the
4216
 
    precision of a signed int
4217
 
  */
4218
 
  return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
4219
 
}
4220
 
 
4221
4133
static int read_line(char *buf, int size)
4222
4134
{
4223
4135
  char c, last_quote= 0;
4476
4388
        end++;
4477
4389
      save= *end;
4478
4390
      *end= 0;
4479
 
      type= command_typelib.find_type(start, 1+2);
 
4391
      type= find_type(start, &command_typelib, 1+2);
4480
4392
      if (type)
4481
4393
        warning_msg("Embedded drizzletest command '--%s' detected in "
4482
4394
                    "query '%s' was this intentional? ",
4541
4453
  return;
4542
4454
}
4543
4455
 
 
4456
 
 
4457
 
4544
4458
/*
4545
4459
  Create a command from a set of lines
4546
4460
 
4558
4472
  terminated by new line '\n' regardless how many "delimiter" it contain.
4559
4473
*/
4560
4474
 
4561
 
#define MAX_QUERY (768*1024*2) /* 256K -- a test in sp-big is >128K */
 
4475
#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */
4562
4476
static char read_command_buf[MAX_QUERY];
4563
4477
 
4564
4478
static int read_command(struct st_command** command_ptr)
4572
4486
    *command_ptr= q_lines[parser.current_line];
4573
4487
    return(0);
4574
4488
  }
4575
 
  if (!(*command_ptr= command= new st_command))
4576
 
    die("command construction failed");
 
4489
  if (!(*command_ptr= command=
 
4490
        (struct st_command*) malloc(sizeof(*command))))
 
4491
    die("command malloc failed");
 
4492
  memset(command, 0, sizeof(*command));
4577
4493
  q_lines.push_back(command);
4578
4494
  command->type= Q_UNKNOWN;
4579
4495
 
4620
4536
  return(0);
4621
4537
}
4622
4538
 
 
4539
 
 
4540
static struct my_option my_long_options[] =
 
4541
{
 
4542
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
4543
   0, 0, 0, 0, 0, 0},
 
4544
  {"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
 
4545
   (char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4546
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
4547
   "Directory where character sets are.", (char**) &opt_charsets_dir,
 
4548
   (char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4549
  {"compress", 'C', "Use the compressed server/client protocol.",
 
4550
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
4551
   0, 0, 0},
 
4552
  {"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
 
4553
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4554
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
4555
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
4556
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4557
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
4558
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
4559
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4560
  {"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
 
4561
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4562
  {"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
 
4563
   (char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4564
  {"testdir", OPT_TESTDIR, "Path to use to search for test files",
 
4565
   (char**) &opt_testdir,
 
4566
   (char**) &opt_testdir, 0,GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4567
  {"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
 
4568
   (char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4569
  {"mark-progress", OPT_MARK_PROGRESS,
 
4570
   "Write linenumber and elapsed time to <testname>.progress ",
 
4571
   (char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
 
4572
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4573
  {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
 
4574
   "Max number of connection attempts when connecting to server",
 
4575
   (char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
 
4576
   GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
 
4577
  {"password", 'P', "Password to use when connecting to server.",
 
4578
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
4579
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
 
4580
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
4581
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
4582
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4583
  {"quiet", 's', "Suppress all normal output.", (char**) &silent,
 
4584
   (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4585
  {"record", 'r', "Record output of test_file into result file.",
 
4586
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4587
  {"result-file", 'R', "Read/Store result from/in this file.",
 
4588
   (char**) &result_file_name, (char**) &result_file_name, 0,
 
4589
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4590
  {"server-arg", 'A', "Send option value to embedded server as a parameter.",
 
4591
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4592
  {"server-file", 'F', "Read embedded server arguments from file.",
 
4593
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4594
  {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
 
4595
   (char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4596
  {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
 
4597
   (char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
 
4598
   0, 0, 0},
 
4599
  {"tail-lines", OPT_TAIL_LINES,
 
4600
   "Number of lines of the resul to include in a failure report",
 
4601
   (char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
 
4602
   GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
 
4603
  {"test-file", 'x', "Read test from/in this file (default stdin).",
 
4604
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4605
  {"timer-file", 'm', "File where the timing in micro seconds is stored.",
 
4606
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4607
  {"tmpdir", 't', "Temporary directory where sockets are put.",
 
4608
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4609
  {"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
 
4610
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4611
  {"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
 
4612
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4613
  {"version", 'V', "Output version information and exit.",
 
4614
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4615
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
4616
};
 
4617
 
 
4618
 
 
4619
static void print_version(void)
 
4620
{
 
4621
  printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",my_progname,MTEST_VERSION,
 
4622
         drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
 
4623
}
 
4624
 
 
4625
static void usage(void)
 
4626
{
 
4627
  print_version();
 
4628
  printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
 
4629
  printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
 
4630
  printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
 
4631
  printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
 
4632
  my_print_help(my_long_options);
 
4633
  printf("  --no-defaults       Don't read default options from any options file.\n");
 
4634
  my_print_variables(my_long_options);
 
4635
}
 
4636
 
 
4637
/*
 
4638
  Read arguments for embedded server and put them into
 
4639
  embedded_server_args[]
 
4640
*/
 
4641
 
 
4642
static void read_embedded_server_arguments(const char *name)
 
4643
{
 
4644
  char argument[1024],buff[FN_REFLEN], *str=0;
 
4645
  FILE *file;
 
4646
 
 
4647
  if (!test_if_hard_path(name))
 
4648
  {
 
4649
    sprintf(buff,"%s%s",opt_basedir,name);
 
4650
    name=buff;
 
4651
  }
 
4652
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
4653
 
 
4654
  if (!embedded_server_arg_count)
 
4655
  {
 
4656
    embedded_server_arg_count=1;
 
4657
    embedded_server_args[0]= (char*) "";    /* Progname */
 
4658
  }
 
4659
  if (!(file= fopen(buff, "r")))
 
4660
    die("Failed to open file '%s'", buff);
 
4661
 
 
4662
  while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
 
4663
         (str=fgets(argument,sizeof(argument), file)))
 
4664
  {
 
4665
    *(strchr(str, '\0')-1)=0;        /* Remove end newline */
 
4666
    if (!(embedded_server_args[embedded_server_arg_count]=
 
4667
          (char*) strdup(str)))
 
4668
    {
 
4669
      fclose(file);
 
4670
      die("Out of memory");
 
4671
 
 
4672
    }
 
4673
    embedded_server_arg_count++;
 
4674
  }
 
4675
  fclose(file);
 
4676
  if (str)
 
4677
    die("Too many arguments in option file: %s",name);
 
4678
 
 
4679
  return;
 
4680
}
 
4681
 
 
4682
 
 
4683
bool get_one_option(int optid, const struct my_option *, char *argument)
 
4684
{
 
4685
  char *endchar= NULL;
 
4686
  uint64_t temp_drizzle_port= 0;
 
4687
 
 
4688
  switch(optid) {
 
4689
  case 'r':
 
4690
    record = 1;
 
4691
    break;
 
4692
  case 'x':
 
4693
  {
 
4694
    char buff[FN_REFLEN];
 
4695
    if (!test_if_hard_path(argument))
 
4696
    {
 
4697
      sprintf(buff,"%s%s",opt_basedir,argument);
 
4698
      argument= buff;
 
4699
    }
 
4700
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4701
    assert(cur_file == file_stack && cur_file->file == 0);
 
4702
    if (!(cur_file->file= fopen(buff, "r")))
 
4703
      die("Could not open '%s' for reading: errno = %d", buff, errno);
 
4704
    if (!(cur_file->file_name= strdup(buff)))
 
4705
      die("Out of memory");
 
4706
    cur_file->lineno= 1;
 
4707
    break;
 
4708
  }
 
4709
  case 'm':
 
4710
  {
 
4711
    static char buff[FN_REFLEN];
 
4712
    if (!test_if_hard_path(argument))
 
4713
    {
 
4714
      sprintf(buff,"%s%s",opt_basedir,argument);
 
4715
      argument= buff;
 
4716
    }
 
4717
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4718
    timer_file= buff;
 
4719
    unlink(timer_file);       /* Ignore error, may not exist */
 
4720
    break;
 
4721
  }
 
4722
  case 'p':
 
4723
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
4724
    /* if there is an alpha character this is not a valid port */
 
4725
    if (strlen(endchar) != 0)
 
4726
    {
 
4727
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
4728
      exit(1);
 
4729
    }
 
4730
    /* If the port number is > 65535 it is not a valid port
 
4731
       This also helps with potential data loss casting unsigned long to a
 
4732
       uint32_t. */
 
4733
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
4734
    {
 
4735
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
4736
      exit(1);
 
4737
    }
 
4738
    else
 
4739
    {
 
4740
      opt_port= (uint32_t) temp_drizzle_port;
 
4741
    }
 
4742
    break;
 
4743
  case 'P':
 
4744
    if (argument)
 
4745
    {
 
4746
      if (opt_pass)
 
4747
        free(opt_pass);
 
4748
      opt_pass = strdup(argument);
 
4749
      if (opt_pass == NULL)
 
4750
        die("Out of memory");
 
4751
      while (*argument)
 
4752
      {
 
4753
        /* Overwriting password with 'x' */
 
4754
        *argument++= 'x';
 
4755
      }
 
4756
      tty_password= 0;
 
4757
    }
 
4758
    else
 
4759
      tty_password= 1;
 
4760
    break;
 
4761
  case 't':
 
4762
    strncpy(TMPDIR, argument, sizeof(TMPDIR));
 
4763
    break;
 
4764
  case 'A':
 
4765
    if (!embedded_server_arg_count)
 
4766
    {
 
4767
      embedded_server_arg_count=1;
 
4768
      embedded_server_args[0]= (char*) "";
 
4769
    }
 
4770
    if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 ||
 
4771
        !(embedded_server_args[embedded_server_arg_count++]=
 
4772
          strdup(argument)))
 
4773
    {
 
4774
      die("Can't use server argument");
 
4775
    }
 
4776
    break;
 
4777
  case 'F':
 
4778
    read_embedded_server_arguments(argument);
 
4779
    break;
 
4780
  case 'V':
 
4781
    print_version();
 
4782
    exit(0);
 
4783
  case '?':
 
4784
    usage();
 
4785
    exit(0);
 
4786
  }
 
4787
  return 0;
 
4788
}
 
4789
 
 
4790
 
 
4791
static int parse_args(int argc, char **argv)
 
4792
{
 
4793
  load_defaults("drizzle",load_default_groups,&argc,&argv);
 
4794
  default_argv= argv;
 
4795
 
 
4796
  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
 
4797
    exit(1);
 
4798
 
 
4799
  if (argc > 1)
 
4800
  {
 
4801
    usage();
 
4802
    exit(1);
 
4803
  }
 
4804
  if (argc == 1)
 
4805
    opt_db= *argv;
 
4806
  if (tty_password)
 
4807
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
 
4808
  if (debug_info_flag)
 
4809
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
4810
  if (debug_check_flag)
 
4811
    my_end_arg= MY_CHECK_ERROR;
 
4812
 
 
4813
  return 0;
 
4814
}
 
4815
 
4623
4816
/*
4624
4817
  Write the content of str into file
4625
4818
 
4636
4829
  int fd;
4637
4830
  char buff[FN_REFLEN];
4638
4831
  int flags= O_WRONLY | O_CREAT;
4639
 
  if (!internal::test_if_hard_path(fname))
 
4832
  if (!test_if_hard_path(fname))
4640
4833
  {
4641
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
 
4834
    sprintf(buff,"%s%s",opt_basedir,fname);
4642
4835
    fname= buff;
4643
4836
  }
4644
 
  internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
 
4837
  fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4645
4838
 
4646
4839
  if (!append)
4647
4840
    flags|= O_TRUNC;
4648
 
  if ((fd= internal::my_open(buff, flags,
 
4841
  if ((fd= my_open(buff, flags,
4649
4842
                   MYF(MY_WME | MY_FFNF))) < 0)
4650
4843
    die("Could not open '%s' for writing: errno = %d", buff, errno);
4651
4844
  if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
4652
4845
    die("Could not find end of file '%s': errno = %d", buff, errno);
4653
 
  if (internal::my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
 
4846
  if (my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
4654
4847
    die("write failed");
4655
 
  internal::my_close(fd, MYF(0));
 
4848
  my_close(fd, MYF(0));
4656
4849
}
4657
4850
 
4658
4851
/*
4674
4867
void dump_result_to_log_file(const char *buf, int size)
4675
4868
{
4676
4869
  char log_file[FN_REFLEN];
4677
 
  str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(), ".log",
4678
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4870
  str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log",
 
4871
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4679
4872
                        MY_REPLACE_EXT),
4680
4873
              buf, size);
4681
4874
  fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
4685
4878
void dump_progress(void)
4686
4879
{
4687
4880
  char progress_file[FN_REFLEN];
4688
 
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4689
 
                        opt_logdir.c_str(), ".progress",
4690
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4881
  str_to_file(fn_format(progress_file, result_file_name,
 
4882
                        opt_logdir, ".progress",
 
4883
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4691
4884
                        MY_REPLACE_EXT),
4692
4885
              ds_progress.c_str(), ds_progress.length());
4693
4886
}
4696
4889
{
4697
4890
  char warn_file[FN_REFLEN];
4698
4891
 
4699
 
  str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(), ".warnings",
4700
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4892
  str_to_file(fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
 
4893
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4701
4894
                        MY_REPLACE_EXT),
4702
4895
              ds_warning_messages.c_str(), ds_warning_messages.length());
4703
4896
}
5001
5194
      }
5002
5195
 
5003
5196
      /*
5004
 
        Need to call drizzle_result_affected_rows() before the "new"
 
5197
        Need to call drizzleclient_affected_rows() before the "new"
5005
5198
        query to find the warnings
5006
5199
      */
5007
5200
      if (!disable_info)
5068
5261
  uint32_t i;
5069
5262
 
5070
5263
 
5071
 
  if (! command->require_file.empty())
 
5264
  if (command->require_file[0])
5072
5265
  {
5073
5266
    /*
5074
5267
      The query after a "--require" failed. This is fine as long the server
5227
5420
    Create a temporary dynamic string to contain the output from
5228
5421
    this query.
5229
5422
  */
5230
 
  if (! command->require_file.empty())
 
5423
  if (command->require_file[0])
5231
5424
  {
5232
5425
    ds= &ds_result;
5233
5426
  }
5270
5463
    ds= save_ds;
5271
5464
  }
5272
5465
 
5273
 
  if (! command->require_file.empty())
 
5466
  if (command->require_file[0])
5274
5467
  {
5275
5468
    /* A result file was specified for _this_ query
5276
5469
       and the output should be checked against an already
5299
5492
 
5300
5493
  save= command->query[command->first_word_len];
5301
5494
  command->query[command->first_word_len]= 0;
5302
 
  type= command_typelib.find_type(command->query, 1+2);
 
5495
  type= find_type(command->query, &command_typelib, 1+2);
5303
5496
  command->query[command->first_word_len]= save;
5304
5497
  if (type > 0)
5305
5498
  {
5343
5536
        */
5344
5537
        save= command->query[command->first_word_len-1];
5345
5538
        command->query[command->first_word_len-1]= 0;
5346
 
        if (command_typelib.find_type(command->query, 1+2) > 0)
 
5539
        if (find_type(command->query, &command_typelib, 1+2) > 0)
5347
5540
          die("Extra delimiter \";\" found");
5348
5541
        command->query[command->first_word_len-1]= save;
5349
5542
 
5395
5588
 
5396
5589
}
5397
5590
 
5398
 
static void check_retries(uint32_t in_opt_max_connect_retries)
5399
 
{
5400
 
  if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5401
 
  {
5402
 
    cout << N_("Error: Invalid Value for opt_max_connect_retries"); 
5403
 
    exit(-1);
5404
 
  }
5405
 
  opt_max_connect_retries= in_opt_max_connect_retries;
5406
 
}
5407
 
 
5408
 
static void check_tail_lines(uint32_t in_opt_tail_lines)
5409
 
{
5410
 
  if (in_opt_tail_lines > 10000)
5411
 
  {
5412
 
    cout << N_("Error: Invalid Value for opt_tail_lines"); 
5413
 
    exit(-1);
5414
 
  }
5415
 
  opt_tail_lines= in_opt_tail_lines;
5416
 
}
5417
 
 
5418
 
static void check_sleep(int32_t in_opt_sleep)
5419
 
{
5420
 
  if (in_opt_sleep < -1)
5421
 
  {
5422
 
    cout << N_("Error: Invalid Value for opt_sleep"); 
5423
 
    exit(-1);
5424
 
  }
5425
 
  opt_sleep= in_opt_sleep;
5426
 
}
5427
5591
 
5428
5592
int main(int argc, char **argv)
5429
5593
{
5430
 
try
5431
 
{
5432
5594
  struct st_command *command;
5433
5595
  bool q_send_flag= 0, abort_flag= 0;
5434
5596
  uint32_t command_executed= 0, last_command_executed= 0;
5435
 
  string save_file("");
 
5597
  char save_file[FN_REFLEN];
5436
5598
  struct stat res_info;
 
5599
  MY_INIT(argv[0]);
5437
5600
 
 
5601
  save_file[0]= 0;
5438
5602
  TMPDIR[0]= 0;
5439
5603
 
5440
 
  internal::my_init();
5441
 
 
5442
 
  po::options_description commandline_options("Options used only in command line");
5443
 
  commandline_options.add_options()
5444
 
  ("help,?", "Display this help and exit.")
5445
 
  ("mark-progress", po::value<bool>(&opt_mark_progress)->default_value(false)->zero_tokens(),
5446
 
  "Write linenumber and elapsed time to <testname>.progress ")
5447
 
  ("sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
5448
 
  "Sleep always this many seconds on sleep commands.")
5449
 
  ("test-file,x", po::value<string>(),
5450
 
  "Read test from/in this file (default stdin).")
5451
 
  ("timer-file,f", po::value<string>(),
5452
 
  "File where the timing in micro seconds is stored.")
5453
 
  ("tmpdir,t", po::value<string>(),
5454
 
  "Temporary directory where sockets are put.")
5455
 
  ("verbose,v", po::value<bool>(&verbose)->default_value(false),
5456
 
  "Write more.")
5457
 
  ("version,V", "Output version information and exit.")
5458
 
  ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
5459
 
  "Configuration file defaults are not used if no-defaults is set")
5460
 
  ;
5461
 
 
5462
 
  po::options_description test_options("Options specific to the drizzleimport");
5463
 
  test_options.add_options()
5464
 
  ("basedir,b", po::value<string>(&opt_basedir)->default_value(""),
5465
 
  "Basedir for tests.")
5466
 
  ("character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(""),
5467
 
  "Directory where character sets are.")
5468
 
  ("database,D", po::value<string>(&opt_db)->default_value(""),
5469
 
  "Database to use.")
5470
 
  ("include,i", po::value<string>(&opt_include)->default_value(""),
5471
 
  "Include SQL before each test case.")  
5472
 
  ("testdir", po::value<string>(&opt_testdir)->default_value(""),
5473
 
  "Path to use to search for test files")
5474
 
  ("logdir", po::value<string>(&opt_logdir)->default_value(""),
5475
 
  "Directory for log files")
5476
 
  ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
5477
 
  "Max number of connection attempts when connecting to server")
5478
 
  ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5479
 
  "Suppress all normal output.")
5480
 
  ("record,r", "Record output of test_file into result file.")
5481
 
  ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
5482
 
  "Read/Store result from/in this file.")
5483
 
  ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5484
 
  "Suppress all normal output. Synonym for --quiet.")
5485
 
  ("tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
5486
 
  "Number of lines of the resul to include in a failure report")
5487
 
  ;
5488
 
 
5489
 
  po::options_description client_options("Options specific to the client");
5490
 
  client_options.add_options()
5491
 
 
5492
 
  ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
5493
 
  "Connect to host.")
5494
 
  ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
5495
 
  "Password to use when connecting to server.")
5496
 
  ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
5497
 
  "Port number to use for connection or 0 for default")
5498
 
  ("protocol", po::value<string>(&opt_protocol),
5499
 
  "The protocol of connection (mysql or drizzle).")
5500
 
  ("user,u", po::value<string>(&opt_user)->default_value(""),
5501
 
  "User for login.")
5502
 
  ;
5503
 
 
5504
 
  po::positional_options_description p;
5505
 
  p.add("database", 1);
5506
 
 
5507
 
  po::options_description long_options("Allowed Options");
5508
 
  long_options.add(commandline_options).add(test_options).add(client_options);
5509
 
 
5510
 
  std::string system_config_dir_test(SYSCONFDIR); 
5511
 
  system_config_dir_test.append("/drizzle/drizzletest.cnf");
5512
 
 
5513
 
  std::string system_config_dir_client(SYSCONFDIR); 
5514
 
  system_config_dir_client.append("/drizzle/client.cnf");
5515
 
 
5516
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5517
 
 
5518
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
5519
 
  {
5520
 
    char *homedir;
5521
 
    homedir= getenv("HOME");
5522
 
    if (homedir != NULL)
5523
 
      user_config_dir.replace(0, 1, homedir);
5524
 
  }
5525
 
 
5526
 
  po::variables_map vm;
5527
 
 
5528
 
  // Disable allow_guessing
5529
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5530
 
 
5531
 
  po::store(po::command_line_parser(argc, argv).options(long_options).
5532
 
            style(style).positional(p).extra_parser(parse_password_arg).run(),
5533
 
            vm);
5534
 
 
5535
 
  if (! vm["no-defaults"].as<bool>())
5536
 
  {
5537
 
    std::string user_config_dir_test(user_config_dir);
5538
 
    user_config_dir_test.append("/drizzle/drizzletest.cnf"); 
5539
 
 
5540
 
    std::string user_config_dir_client(user_config_dir);
5541
 
    user_config_dir_client.append("/drizzle/client.cnf");
5542
 
 
5543
 
    ifstream user_test_ifs(user_config_dir_test.c_str());
5544
 
    po::store(parse_config_file(user_test_ifs, test_options), vm);
5545
 
 
5546
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
5547
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
5548
 
 
5549
 
    ifstream system_test_ifs(system_config_dir_test.c_str());
5550
 
    store(parse_config_file(system_test_ifs, test_options), vm);
5551
 
 
5552
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
5553
 
    po::store(parse_config_file(system_client_ifs, client_options), vm);
5554
 
  }
5555
 
 
5556
 
  po::notify(vm);
5557
 
 
5558
5604
  /* Init expected errors */
5559
5605
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5560
5606
 
5578
5624
  cur_block->ok= true; /* Outer block should always be executed */
5579
5625
  cur_block->cmd= cmd_none;
5580
5626
 
 
5627
  if (hash_init(&var_hash, charset_info,
 
5628
                1024, 0, 0, get_var_key, var_free, MYF(0)))
 
5629
    die("Variable hash initialization failed");
 
5630
 
5581
5631
  var_set_string("$DRIZZLE_SERVER_VERSION", drizzle_version());
5582
5632
 
5583
5633
  memset(&master_pos, 0, sizeof(master_pos));
5591
5641
  ds_progress.reserve(2048);
5592
5642
  ds_warning_messages.reserve(2048);
5593
5643
 
5594
 
 
5595
 
  if (vm.count("record"))
5596
 
  {
5597
 
    record = 1;
5598
 
  }
5599
 
 
5600
 
  if (vm.count("test-file"))
5601
 
  {
5602
 
    string tmp= vm["test-file"].as<string>();
5603
 
    char buff[FN_REFLEN];
5604
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5605
 
    {
5606
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5607
 
      tmp= buff;
5608
 
    }
5609
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5610
 
    assert(cur_file == file_stack && cur_file->file == 0);
5611
 
    if (!(cur_file->file= fopen(buff, "r")))
5612
 
    {
5613
 
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5614
 
      return EXIT_ARGUMENT_INVALID;
5615
 
    }
5616
 
    if (!(cur_file->file_name= strdup(buff)))
5617
 
    {
5618
 
      fprintf(stderr, _("Out of memory"));
5619
 
      return EXIT_OUT_OF_MEMORY;
5620
 
    }
5621
 
    cur_file->lineno= 1;
5622
 
  }
5623
 
 
5624
 
  if (vm.count("timer-file"))
5625
 
  {
5626
 
    string tmp= vm["timer-file"].as<string>().c_str();
5627
 
    static char buff[FN_REFLEN];
5628
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5629
 
    {
5630
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5631
 
      tmp= buff;
5632
 
    }
5633
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5634
 
    timer_file= buff;
5635
 
    unlink(timer_file);       /* Ignore error, may not exist */
5636
 
  }
5637
 
 
5638
 
  if (vm.count("protocol"))
5639
 
  {
5640
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
5641
 
      opt_protocol.begin(), ::tolower);
5642
 
 
5643
 
    if (not opt_protocol.compare("mysql"))
5644
 
      use_drizzle_protocol=false;
5645
 
    else if (not opt_protocol.compare("drizzle"))
5646
 
      use_drizzle_protocol=true;
5647
 
    else
5648
 
    {
5649
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5650
 
      exit(-1);
5651
 
    }
5652
 
  }
5653
 
 
5654
 
  if (vm.count("port"))
5655
 
  {
5656
 
    /* If the port number is > 65535 it is not a valid port
5657
 
       This also helps with potential data loss casting unsigned long to a
5658
 
       uint32_t. */
5659
 
    if (opt_port > 65535)
5660
 
    {
5661
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
5662
 
      exit(EXIT_ARGUMENT_INVALID);
5663
 
    }
5664
 
  }
5665
 
 
5666
 
  if( vm.count("password") )
5667
 
  {
5668
 
    if (!opt_password.empty())
5669
 
      opt_password.erase();
5670
 
    if (password == PASSWORD_SENTINEL)
5671
 
    {
5672
 
      opt_password= "";
5673
 
    }
5674
 
    else
5675
 
    {
5676
 
      opt_password= password;
5677
 
      tty_password= false;
5678
 
    }
5679
 
  }
5680
 
  else
5681
 
  {
5682
 
      tty_password= true;
5683
 
  }
5684
 
 
5685
 
  if (vm.count("tmpdir"))
5686
 
  {
5687
 
    strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
5688
 
  }
5689
 
 
5690
 
  if (vm.count("version"))
5691
 
  {
5692
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5693
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5694
 
    exit(0);
5695
 
  }
5696
 
  
5697
 
  if (vm.count("help"))
5698
 
  {
5699
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5700
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5701
 
    printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
5702
 
    printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5703
 
    printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
5704
 
    printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5705
 
    printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5706
 
    exit(0);
5707
 
  }
5708
 
 
5709
 
  if (tty_password)
5710
 
  {
5711
 
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
5712
 
  }
 
5644
  parse_args(argc, argv);
5713
5645
 
5714
5646
  server_initialized= 1;
5715
5647
  if (cur_file == file_stack && cur_file->file == 0)
5725
5657
    die("Failed in drizzle_create()");
5726
5658
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5727
5659
    die("Failed in drizzle_con_create()");
5728
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
5729
5660
 
5730
5661
  if (!(cur_con->name = strdup("default")))
5731
5662
    die("Out of memory");
 
5663
 
5732
5664
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5733
5665
               opt_db, opt_port);
5734
5666
 
5735
 
  fill_global_error_names();
5736
 
 
5737
5667
  /* Use all time until exit if no explicit 'start_timer' */
5738
5668
  timer_start= timer_now();
5739
5669
 
5747
5677
  /* Update $drizzleclient_get_server_version to that of current connection */
5748
5678
  var_set_drizzleclient_get_server_version(&cur_con->con);
5749
5679
 
5750
 
  if (! opt_include.empty())
 
5680
  if (opt_include)
5751
5681
  {
5752
 
    open_file(opt_include.c_str());
 
5682
    open_file(opt_include);
5753
5683
  }
5754
5684
 
5755
5685
  while (!read_command(&command) && !abort_flag)
5863
5793
        /* Check for special property for this query */
5864
5794
        display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
5865
5795
 
5866
 
        if (! save_file.empty())
 
5796
        if (save_file[0])
5867
5797
        {
5868
 
          command->require_file= save_file;
5869
 
          save_file.clear();
 
5798
          strncpy(command->require_file, save_file, sizeof(save_file) - 1);
 
5799
          save_file[0]= 0;
5870
5800
        }
5871
5801
        run_query(cur_con, command, flags);
5872
5802
        command_executed++;
5903
5833
        command->last_argument= command->end;
5904
5834
        break;
5905
5835
      case Q_REQUIRE:
5906
 
        do_get_file_name(command, save_file);
 
5836
        do_get_file_name(command, save_file, sizeof(save_file));
5907
5837
        break;
5908
5838
      case Q_ERROR:
5909
5839
        do_get_errcodes(command);
6053
5983
  */
6054
5984
  if (ds_res.length())
6055
5985
  {
6056
 
    if (! result_file_name.empty())
 
5986
    if (result_file_name)
6057
5987
    {
6058
5988
      /* A result file has been specified */
6059
5989
 
6060
5990
      if (record)
6061
5991
      {
6062
5992
        /* Recording - dump the output from test to result file */
6063
 
        str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
 
5993
        str_to_file(result_file_name, ds_res.c_str(), ds_res.length());
6064
5994
      }
6065
5995
      else
6066
5996
      {
6083
6013
  }
6084
6014
 
6085
6015
  if (!command_executed &&
6086
 
      ! result_file_name.empty() && !stat(result_file_name.c_str(), &res_info))
 
6016
      result_file_name && !stat(result_file_name, &res_info))
6087
6017
  {
6088
6018
    /*
6089
6019
      my_stat() successful on result file. Check if we have not run a
6095
6025
    die("No queries executed but result file found!");
6096
6026
  }
6097
6027
 
6098
 
  if ( opt_mark_progress && ! result_file_name.empty() )
 
6028
  if ( opt_mark_progress && result_file_name )
6099
6029
    dump_progress();
6100
6030
 
6101
6031
  /* Dump warning messages */
6102
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
6032
  if (result_file_name && ds_warning_messages.length())
6103
6033
    dump_warning_messages();
6104
6034
 
6105
6035
  timer_output();
6106
6036
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
6107
6037
  cleanup_and_exit(0);
6108
 
}
6109
 
 
6110
 
  catch(exception &err)
6111
 
  {
6112
 
    cerr<<err.what()<<endl;
6113
 
  }
6114
 
 
6115
6038
  return 0; /* Keep compiler happy too */
6116
6039
}
6117
6040
 
6153
6076
 
6154
6077
uint64_t timer_now(void)
6155
6078
{
6156
 
#if defined(HAVE_GETHRTIME)
6157
 
  return gethrtime()/1000/1000;
6158
 
#else
6159
 
  uint64_t newtime;
6160
 
  struct timeval t;
6161
 
  /*
6162
 
    The following loop is here because gettimeofday may fail on some systems
6163
 
  */
6164
 
  while (gettimeofday(&t, NULL) != 0)
6165
 
  {}
6166
 
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
6167
 
  return newtime/1000;
6168
 
#endif  /* defined(HAVE_GETHRTIME) */
 
6079
  return my_micro_time() / 1000;
6169
6080
}
6170
6081
 
6171
6082
 
6380
6291
  char* pattern; /* Pattern to be replaced */
6381
6292
  char* replace; /* String or expression to replace the pattern with */
6382
6293
  int icase; /* true if the match is case insensitive */
6383
 
  int global; /* true if the match should be global -- 
6384
 
                 i.e. repeat the matching until the end of the string */
6385
6294
};
6386
6295
 
6387
6296
struct st_replace_regex
6405
6314
struct st_replace_regex *glob_replace_regex= 0;
6406
6315
 
6407
6316
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6408
 
                char *string, int icase, int global);
 
6317
                char *string, int icase);
6409
6318
 
6410
6319
 
6411
6320
 
6506
6415
 
6507
6416
    /* Check if we should do matching case insensitive */
6508
6417
    if (p < expr_end && *p == 'i')
6509
 
    {
6510
 
      p++;
6511
6418
      reg.icase= 1;
6512
 
    }
6513
 
 
6514
 
    /* Check if we should do matching globally */
6515
 
    if (p < expr_end && *p == 'g')
6516
 
    {
6517
 
      p++;
6518
 
      reg.global= 1;
6519
 
    }
6520
6419
 
6521
6420
    /* done parsing the statement, now place it in regex_arr */
6522
6421
    if (insert_dynamic(&res->regex_arr,(unsigned char*) &reg))
6574
6473
    get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
6575
6474
 
6576
6475
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
6577
 
                     in_buf, re.icase, re.global))
 
6476
                     in_buf, re.icase))
6578
6477
    {
6579
6478
      /* if the buffer has been reallocated, make adjustements */
6580
6479
      if (save_out_buf != out_buf)
6644
6543
  icase - flag, if set to 1 the match is case insensitive
6645
6544
*/
6646
6545
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
6647
 
                char *replace, char *in_string, int icase, int global)
 
6546
                char *replace, char *in_string, int icase)
6648
6547
{
 
6548
  string string_to_match(in_string);
6649
6549
  const char *error= NULL;
6650
6550
  int erroffset;
6651
6551
  int ovector[3];
6652
6552
  pcre *re= pcre_compile(pattern,
6653
 
                         icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
 
6553
                         icase ? PCRE_CASELESS : 0,
6654
6554
                         &error, &erroffset, NULL);
6655
6555
  if (re == NULL)
6656
6556
    return 1;
6657
6557
 
6658
 
  if (! global)
6659
 
  {
6660
 
 
6661
 
    int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6662
 
                      0, 0, ovector, 3);
6663
 
    if (rc < 0)
6664
 
    {
6665
 
      pcre_free(re);
6666
 
      return 1;
6667
 
    }
6668
 
 
6669
 
    char *substring_to_replace= in_string + ovector[0];
6670
 
    int substring_length= ovector[1] - ovector[0];
6671
 
    *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6672
 
    char * new_buf = (char *)malloc(*buf_len_p+1);
6673
 
    if (new_buf == NULL)
6674
 
    {
6675
 
      pcre_free(re);
6676
 
      return 1;
6677
 
    }
6678
 
 
6679
 
    memset(new_buf, 0, *buf_len_p+1);
6680
 
    strncpy(new_buf, in_string, substring_to_replace-in_string);
6681
 
    strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6682
 
    strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6683
 
            substring_to_replace + substring_length,
6684
 
            strlen(in_string)
6685
 
              - substring_length
6686
 
              - (substring_to_replace-in_string));
6687
 
    *buf_p= new_buf;
6688
 
 
6689
 
    pcre_free(re);
6690
 
    return 0;
6691
 
  }
6692
 
  else
6693
 
  {
6694
 
    /* Repeatedly replace the string with the matched regex */
6695
 
    string subject(in_string);
6696
 
    size_t replace_length= strlen(replace);
6697
 
    size_t length_of_replacement= strlen(replace);
6698
 
    size_t current_position= 0;
6699
 
    int rc= 0;
6700
 
 
6701
 
    while (true) 
6702
 
    {
6703
 
      rc= pcre_exec(re, NULL, subject.c_str(), subject.length(), 
6704
 
                    current_position, 0, ovector, 3);
6705
 
      if (rc < 0)
6706
 
      {
6707
 
        break;
6708
 
      }
6709
 
 
6710
 
      current_position= static_cast<size_t>(ovector[0]);
6711
 
      replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6712
 
      subject.replace(current_position, replace_length, replace, length_of_replacement);
6713
 
      current_position= current_position + length_of_replacement;
6714
 
    }
6715
 
 
6716
 
    char *new_buf = (char *) malloc(subject.length() + 1);
6717
 
    if (new_buf == NULL)
6718
 
    {
6719
 
      pcre_free(re);
6720
 
      return 1;
6721
 
    }
6722
 
    memset(new_buf, 0, subject.length() + 1);
6723
 
    strncpy(new_buf, subject.c_str(), subject.length());
6724
 
    *buf_len_p= subject.length() + 1;
6725
 
    *buf_p= new_buf;
6726
 
          
6727
 
    pcre_free(re);
6728
 
    return 0;
6729
 
  }
 
6558
  int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
 
6559
                    0, 0, ovector, 3);
 
6560
  if (rc < 0)
 
6561
  {
 
6562
    pcre_free(re);
 
6563
    return 1;
 
6564
  }
 
6565
 
 
6566
  char *substring_to_replace= in_string + ovector[0];
 
6567
  int substring_length= ovector[1] - ovector[0];
 
6568
  *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
 
6569
  char * new_buf = (char *)malloc(*buf_len_p+1);
 
6570
  if (new_buf == NULL)
 
6571
  {
 
6572
    pcre_free(re);
 
6573
    return 1;
 
6574
  }
 
6575
 
 
6576
  memset(new_buf, 0, *buf_len_p+1);
 
6577
  strncpy(new_buf, in_string, substring_to_replace-in_string);
 
6578
  strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
 
6579
  strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
 
6580
          substring_to_replace + substring_length,
 
6581
          strlen(in_string)
 
6582
            - substring_length
 
6583
            - (substring_to_replace-in_string));
 
6584
  *buf_p= new_buf;
 
6585
 
 
6586
  pcre_free(re);
 
6587
  return 0;
6730
6588
}
6731
6589
 
6732
6590
 
7310
7168
      return(1);
7311
7169
    if (new_pos != pa->str)
7312
7170
    {
7313
 
      ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
 
7171
      my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
7314
7172
      for (i=0 ; i < pa->typelib.count ; i++)
7315
7173
        pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
7316
7174
                                              char*);