~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

  • Committer: Monty Taylor
  • Date: 2009-04-25 19:24:49 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 1003.
  • Revision ID: mordred@inaugust.com-20090425192449-0htujbt2r9jzupn5
Moved heap.

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
 
#include <algorithm>
52
 
#ifdef HAVE_SYS_WAIT_H
53
 
#include <sys/wait.h>
54
 
#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
49
 
61
50
#include PCRE_HEADER
62
51
 
 
52
#include <mysys/hash.h>
63
53
#include <stdarg.h>
64
 
#include <boost/unordered_map.hpp>
 
54
 
 
55
#include "errname.h"
65
56
 
66
57
/* Added this for string translation. */
67
 
#include "drizzled/gettext.h"
68
 
#include "drizzled/drizzle_time.h"
69
 
#include "drizzled/charset.h"
70
 
#include <drizzled/configmake.h>
 
58
#include <drizzled/gettext.h>
71
59
 
72
 
#ifndef DRIZZLE_RETURN_SERVER_GONE
73
 
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
74
 
#endif
75
 
namespace po= boost::program_options;
76
60
using namespace std;
77
 
using namespace drizzled;
78
 
 
79
 
extern "C"
80
 
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
81
 
 
82
 
int get_one_option(int optid, const struct option *, char *argument);
83
61
 
84
62
#define MAX_VAR_NAME_LENGTH    256
85
63
#define MAX_COLUMNS            256
 
64
#define MAX_EMBEDDED_SERVER_ARGS 64
86
65
#define MAX_DELIMITER_LENGTH 16
87
66
/* Flags controlling send and reap */
88
67
#define QUERY_SEND_FLAG  1
89
68
#define QUERY_REAP_FLAG  2
90
69
 
91
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
92
 
ErrorCodes global_error_names;
93
 
 
94
70
enum {
95
71
  OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
96
72
  OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
98
74
};
99
75
 
100
76
static int record= 0, opt_sleep= -1;
101
 
static char *opt_pass= NULL;
102
 
const char *unix_sock= NULL;
 
77
static char *opt_db= NULL, *opt_pass= NULL;
 
78
const char *opt_user= NULL, *opt_host= NULL, *unix_sock= NULL,
 
79
           *opt_basedir= "./";
 
80
const char *opt_logdir= "";
 
81
const char *opt_include= NULL, *opt_charsets_dir;
 
82
const char *opt_testdir= NULL;
103
83
static uint32_t opt_port= 0;
104
 
static uint32_t opt_max_connect_retries;
105
 
static bool silent= false, verbose= false;
 
84
static int opt_max_connect_retries;
 
85
static bool opt_compress= false, silent= false, verbose= false;
 
86
static bool debug_info_flag= false, debug_check_flag= false;
 
87
static bool tty_password= false;
106
88
static bool opt_mark_progress= false;
107
89
static bool parsing_disabled= false;
108
90
static bool display_result_vertically= false,
113
95
static bool abort_on_error= true;
114
96
static bool server_initialized= false;
115
97
static bool is_windows= false;
116
 
static bool use_drizzle_protocol= false;
 
98
static char **default_argv;
 
99
static const char *load_default_groups[]= { "drizzletest", "client", 0 };
117
100
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
118
101
 
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
102
static uint32_t start_lineno= 0; /* Start line of current command */
 
103
static uint32_t my_end_arg= 0;
133
104
 
134
105
/* Number of lines of the result to include in failure report */
135
106
static uint32_t opt_tail_lines= 0;
171
142
 
172
143
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
173
144
 
 
145
static int embedded_server_arg_count=0;
 
146
static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS];
 
147
 
174
148
/*
175
149
  Timer related variables
176
150
  See the timer_output() definition for details
198
172
master_pos_st master_pos;
199
173
 
200
174
/* if set, all results are concated and compared against this file */
 
175
const char *result_file_name= NULL;
201
176
 
202
177
typedef struct st_var
203
178
{
215
190
/*Perl/shell-like variable registers */
216
191
VAR var_reg[10];
217
192
 
218
 
 
219
 
boost::unordered_map<string, VAR *> var_hash;
 
193
HASH var_hash;
220
194
 
221
195
struct st_connection
222
196
{
396
370
  char *query, *query_buf,*first_argument,*last_argument,*end;
397
371
  int first_word_len, query_len;
398
372
  bool abort_on_error;
399
 
  st_expected_errors expected_errors;
400
 
  string require_file;
 
373
  struct st_expected_errors expected_errors;
 
374
  char require_file[FN_REFLEN];
401
375
  enum enum_commands type;
402
 
 
403
 
  st_command()
404
 
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
405
 
      end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
406
 
      require_file(""), type(Q_CONNECTION)
407
 
  {
408
 
    memset(&expected_errors, 0, sizeof(st_expected_errors));
409
 
  }
410
 
 
411
 
  ~st_command()
412
 
  {
413
 
    if (query_buf != NULL)
414
 
    {
415
 
      free(query_buf);
416
 
    }
417
 
  }
418
376
};
419
377
 
420
378
TYPELIB command_typelib= {array_elements(command_names),"",
438
396
VAR* var_from_env(const char *, const char *);
439
397
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
440
398
              int val_len);
441
 
void var_free(pair<string, VAR*> v);
 
399
extern "C" void var_free(void* v);
442
400
VAR* var_get(const char *var_name, const char** var_name_end,
443
401
             bool raw, bool ignore_not_existing);
444
402
void eval_expr(VAR* v, const char *p, const char** p_end);
559
517
  options are passed.
560
518
*/
561
519
 
562
 
static void append_os_quoted(string *str, const char *append, ...)
 
520
void append_os_quoted(string *str, const char *append, ...)
563
521
{
564
522
  const char *quote_str= "\'";
565
523
  const uint32_t  quote_len= 1;
780
738
  for (i= 0; i < num_args; i++)
781
739
  {
782
740
    const struct command_arg *arg= &args[i];
783
 
    arg->ds->clear();
784
741
 
785
 
    bool known_arg_type= true;
786
742
    switch (arg->type) {
787
743
      /* A string */
788
744
    case ARG_STRING:
817
773
      break;
818
774
 
819
775
    default:
820
 
      known_arg_type= false;
 
776
      assert("Unknown argument type");
821
777
      break;
822
778
    }
823
 
    assert(known_arg_type);
824
779
 
825
780
    /* Check required arg */
826
781
    if (arg->ds->length() == 0 && arg->required)
912
867
 
913
868
  close_connections();
914
869
  close_files();
915
 
  for_each(var_hash.begin(), var_hash.end(), var_free);
916
 
  var_hash.clear();
 
870
  hash_free(&var_hash);
917
871
 
918
 
  vector<st_command *>::iterator iter;
 
872
  vector<struct st_command *>::iterator iter;
919
873
  for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
920
874
  {
921
875
    struct st_command * q_line= *iter;
922
 
    delete q_line;
 
876
    if (q_line->query_buf != NULL)
 
877
    {
 
878
      free(q_line->query_buf);
 
879
    }
 
880
    free(q_line);
923
881
  }
924
882
 
925
883
  for (i= 0; i < 10; i++)
927
885
    if (var_reg[i].alloced_len)
928
886
      free(var_reg[i].str_val);
929
887
  }
 
888
  while (embedded_server_arg_count > 1)
 
889
    free(embedded_server_args[--embedded_server_arg_count]);
930
890
 
931
891
  free_all_replace();
932
892
  free(opt_pass);
 
893
  free_defaults(default_argv);
933
894
 
934
895
  return;
935
896
}
938
899
static void cleanup_and_exit(int exit_code)
939
900
{
940
901
  free_used_memory();
941
 
  internal::my_end();
 
902
  my_end(my_end_arg);
942
903
 
943
904
  if (!silent) {
944
905
    switch (exit_code) {
1011
972
  }
1012
973
 
1013
974
  /* Dump the result that has been accumulated so far to .log file */
1014
 
  if (! result_file_name.empty() && ds_res.length())
 
975
  if (result_file_name && ds_res.length())
1015
976
    dump_result_to_log_file(ds_res.c_str(), ds_res.length());
1016
977
 
1017
978
  /* Dump warning messages */
1018
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
979
  if (result_file_name && ds_warning_messages.length())
1019
980
    dump_warning_messages();
1020
981
 
1021
982
  /*
1151
1112
  uint32_t len;
1152
1113
  char buff[512];
1153
1114
 
1154
 
  if ((fd= internal::my_open(filename, O_RDONLY, MYF(0))) < 0)
 
1115
  if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0)
1155
1116
    die("Failed to open file '%s'", filename);
1156
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1117
  while((len= my_read(fd, (unsigned char*)&buff,
1157
1118
                      sizeof(buff), MYF(0))) > 0)
1158
1119
  {
1159
1120
    char *p= buff, *start= buff;
1175
1136
    /* Output any chars that might be left */
1176
1137
    ds->append(start, p-start);
1177
1138
  }
1178
 
  internal::my_close(fd, MYF(0));
 
1139
  my_close(fd, MYF(0));
1179
1140
}
1180
1141
 
1181
1142
 
1351
1312
 
1352
1313
*/
1353
1314
 
1354
 
static int compare_files2(int fd, const char* filename2)
 
1315
static int compare_files2(File fd, const char* filename2)
1355
1316
{
1356
1317
  int error= RESULT_OK;
1357
 
  int fd2;
 
1318
  File fd2;
1358
1319
  uint32_t len, len2;
1359
1320
  char buff[512], buff2[512];
1360
1321
  const char *fname= filename2;
1361
1322
  string tmpfile;
1362
1323
 
1363
 
  if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
 
1324
  if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1364
1325
  {
1365
 
    internal::my_close(fd, MYF(0));
1366
 
    if (! opt_testdir.empty())
 
1326
    my_close(fd, MYF(0));
 
1327
    if (opt_testdir != NULL)
1367
1328
    {
1368
1329
      tmpfile= opt_testdir;
1369
1330
      if (tmpfile[tmpfile.length()] != '/')
1371
1332
      tmpfile.append(filename2);
1372
1333
      fname= tmpfile.c_str();
1373
1334
    }
1374
 
    if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
 
1335
    if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1375
1336
    {
1376
 
      internal::my_close(fd, MYF(0));
 
1337
      my_close(fd, MYF(0));
1377
1338
    
1378
1339
      die("Failed to open second file: '%s'", fname);
1379
1340
    }
1380
1341
  }
1381
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1342
  while((len= my_read(fd, (unsigned char*)&buff,
1382
1343
                      sizeof(buff), MYF(0))) > 0)
1383
1344
  {
1384
 
    if ((len2= internal::my_read(fd2, (unsigned char*)&buff2,
 
1345
    if ((len2= my_read(fd2, (unsigned char*)&buff2,
1385
1346
                       sizeof(buff2), MYF(0))) < len)
1386
1347
    {
1387
1348
      /* File 2 was smaller */
1401
1362
      break;
1402
1363
    }
1403
1364
  }
1404
 
  if (!error && internal::my_read(fd2, (unsigned char*)&buff2,
 
1365
  if (!error && my_read(fd2, (unsigned char*)&buff2,
1405
1366
                        sizeof(buff2), MYF(0)) > 0)
1406
1367
  {
1407
1368
    /* File 1 was smaller */
1408
1369
    error= RESULT_LENGTH_MISMATCH;
1409
1370
  }
1410
1371
 
1411
 
  internal::my_close(fd2, MYF(0));
 
1372
  my_close(fd2, MYF(0));
1412
1373
 
1413
1374
  return error;
1414
1375
}
1429
1390
 
1430
1391
static int compare_files(const char* filename1, const char* filename2)
1431
1392
{
1432
 
  int fd;
 
1393
  File fd;
1433
1394
  int error;
1434
1395
 
1435
 
  if ((fd= internal::my_open(filename1, O_RDONLY, MYF(0))) < 0)
 
1396
  if ((fd= my_open(filename1, O_RDONLY, MYF(0))) < 0)
1436
1397
    die("Failed to open first file: '%s'", filename1);
1437
1398
 
1438
1399
  error= compare_files2(fd, filename2);
1439
1400
 
1440
 
  internal::my_close(fd, MYF(0));
 
1401
  my_close(fd, MYF(0));
1441
1402
 
1442
1403
  return error;
1443
1404
}
1458
1419
static int string_cmp(string* ds, const char *fname)
1459
1420
{
1460
1421
  int error;
1461
 
  int fd;
 
1422
  File fd;
1462
1423
  char temp_file_path[FN_REFLEN];
1463
1424
 
1464
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
1465
 
                            "tmp", MYF(MY_WME))) < 0)
 
1425
  if ((fd= create_temp_file(temp_file_path, NULL,
 
1426
                            "tmp", O_CREAT | O_RDWR,
 
1427
                            MYF(MY_WME))) < 0)
1466
1428
    die("Failed to create temporary file for ds");
1467
1429
 
1468
1430
  /* Write ds to temporary file and set file pos to beginning*/
1469
 
  if (internal::my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
 
1431
  if (my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
1470
1432
               MYF(MY_FNABP | MY_WME)) ||
1471
1433
      lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
1472
1434
  {
1473
 
    internal::my_close(fd, MYF(0));
 
1435
    my_close(fd, MYF(0));
1474
1436
    /* Remove the temporary file */
1475
 
    internal::my_delete(temp_file_path, MYF(0));
 
1437
    my_delete(temp_file_path, MYF(0));
1476
1438
    die("Failed to write file '%s'", temp_file_path);
1477
1439
  }
1478
1440
 
1479
1441
  error= compare_files2(fd, fname);
1480
1442
 
1481
 
  internal::my_close(fd, MYF(0));
 
1443
  my_close(fd, MYF(0));
1482
1444
  /* Remove the temporary file */
1483
 
  internal::my_delete(temp_file_path, MYF(0));
 
1445
  my_delete(temp_file_path, MYF(0));
1484
1446
 
1485
1447
  return(error);
1486
1448
}
1503
1465
  const char* mess= "Result content mismatch\n";
1504
1466
 
1505
1467
 
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())) {
 
1468
  assert(result_file_name);
 
1469
 
 
1470
  if (access(result_file_name, F_OK) != 0)
 
1471
    die("The specified result file does not exist: '%s'", result_file_name);
 
1472
 
 
1473
  switch (string_cmp(ds, result_file_name)) {
1512
1474
  case RESULT_OK:
1513
1475
    break; /* ok */
1514
1476
  case RESULT_LENGTH_MISMATCH:
1522
1484
    */
1523
1485
    char reject_file[FN_REFLEN];
1524
1486
    size_t reject_length;
1525
 
    internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
 
1487
    dirname_part(reject_file, result_file_name, &reject_length);
1526
1488
 
1527
1489
    if (access(reject_file, W_OK) == 0)
1528
1490
    {
1529
1491
      /* Result file directory is writable, save reject file there */
1530
 
      internal::fn_format(reject_file, result_file_name.c_str(), NULL,
 
1492
      fn_format(reject_file, result_file_name, NULL,
1531
1493
                ".reject", MY_REPLACE_EXT);
1532
1494
    }
1533
1495
    else
1534
1496
    {
1535
1497
      /* Put reject file in opt_logdir */
1536
 
      internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
 
1498
      fn_format(reject_file, result_file_name, opt_logdir,
1537
1499
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1538
1500
    }
1539
1501
    str_to_file(reject_file, ds->c_str(), ds->length());
1540
1502
 
1541
1503
    ds->erase(); /* Don't create a .log file */
1542
1504
 
1543
 
    show_diff(NULL, result_file_name.c_str(), reject_file);
 
1505
    show_diff(NULL, result_file_name, reject_file);
1544
1506
    die("%s",mess);
1545
1507
    break;
1546
1508
  }
1567
1529
 
1568
1530
*/
1569
1531
 
1570
 
static void check_require(string* ds, const string &fname)
 
1532
static void check_require(string* ds, const char *fname)
1571
1533
{
1572
1534
 
1573
1535
 
1574
 
  if (string_cmp(ds, fname.c_str()))
 
1536
  if (string_cmp(ds, fname))
1575
1537
  {
1576
1538
    char reason[FN_REFLEN];
1577
 
    internal::fn_format(reason, fname.c_str(), "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
 
1539
    fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
1578
1540
    abort_not_supported_test("Test requires: '%s'", reason);
1579
1541
  }
1580
1542
  return;
1625
1587
}
1626
1588
 
1627
1589
 
 
1590
extern "C"
 
1591
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool)
 
1592
{
 
1593
  register char* key;
 
1594
  key = ((VAR*)var)->name;
 
1595
  *len = ((VAR*)var)->name_len;
 
1596
  return (unsigned char*)key;
 
1597
}
 
1598
 
1628
1599
 
1629
1600
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1630
1601
              int val_len)
1662
1633
}
1663
1634
 
1664
1635
 
1665
 
void var_free(pair<string, VAR *> v)
 
1636
void var_free(void *v)
1666
1637
{
1667
 
  free(v.second->str_val);
1668
 
  free(v.second->env_s);
1669
 
  if (v.second->alloced)
1670
 
    free(v.second);
 
1638
  free(((VAR*) v)->str_val);
 
1639
  free(((VAR*) v)->env_s);
 
1640
  if (((VAR*)v)->alloced)
 
1641
    free(v);
1671
1642
}
1672
1643
 
1673
1644
 
1679
1650
    tmp = def_val;
1680
1651
 
1681
1652
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
1682
 
  string var_name(name);
1683
 
  var_hash.insert(make_pair(var_name, v));
 
1653
  my_hash_insert(&var_hash, (unsigned char*)v);
1684
1654
  return v;
1685
1655
}
1686
1656
 
1711
1681
    if (length >= MAX_VAR_NAME_LENGTH)
1712
1682
      die("Too long variable name: %s", save_var_name);
1713
1683
 
1714
 
    string save_var_name_str(save_var_name, length);
1715
 
    boost::unordered_map<string, VAR*>::iterator iter=
1716
 
      var_hash.find(save_var_name_str);
1717
 
    if (iter == var_hash.end())
 
1684
    if (!(v = (VAR*) hash_search(&var_hash, (const unsigned char*) save_var_name,
 
1685
                                 length)))
1718
1686
    {
1719
1687
      char buff[MAX_VAR_NAME_LENGTH+1];
1720
1688
      strncpy(buff, save_var_name, length);
1721
1689
      buff[length]= '\0';
1722
1690
      v= var_from_env(buff, "");
1723
1691
    }
1724
 
    else
1725
 
    {
1726
 
      v= (*iter).second;
1727
 
    }
1728
1692
    var_name--;  /* Point at last character */
1729
1693
  }
1730
1694
  else
1749
1713
 
1750
1714
static VAR *var_obtain(const char *name, int len)
1751
1715
{
1752
 
  string var_name(name, len);
1753
 
  boost::unordered_map<string, VAR*>::iterator iter=
1754
 
    var_hash.find(var_name);
1755
 
  if (iter != var_hash.end())
1756
 
    return (*iter).second;
1757
 
  VAR *v = var_init(0, name, len, "", 0);
1758
 
  var_hash.insert(make_pair(var_name, v));
 
1716
  VAR* v;
 
1717
  if ((v = (VAR*)hash_search(&var_hash, (const unsigned char *) name, len)))
 
1718
    return v;
 
1719
  v = var_init(0, name, len, "", 0);
 
1720
  my_hash_insert(&var_hash, (unsigned char*)v);
1759
1721
  return v;
1760
1722
}
1761
1723
 
2117
2079
    const size_t len= strlen(get_value_str);
2118
2080
    if (strncmp(p, get_value_str, len)==0)
2119
2081
    {
2120
 
      st_command command;
 
2082
      struct st_command command;
 
2083
      memset(&command, 0, sizeof(command));
2121
2084
      command.query= (char*)p;
2122
2085
      command.first_word_len= len;
2123
2086
      command.first_argument= command.query + len;
2154
2117
{
2155
2118
  char buff[FN_REFLEN];
2156
2119
 
2157
 
  if (!internal::test_if_hard_path(name))
 
2120
  if (!test_if_hard_path(name))
2158
2121
  {
2159
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
 
2122
    sprintf(buff,"%s%s",opt_basedir,name);
2160
2123
    name=buff;
2161
2124
  }
2162
 
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
2125
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2163
2126
 
2164
2127
  if (cur_file == file_stack_end)
2165
2128
    die("Source directives are nesting too deep");
2210
2173
    ; /* Do nothing */
2211
2174
  else
2212
2175
  {
2213
 
    if (! opt_testdir.empty())
 
2176
    if (opt_testdir != NULL)
2214
2177
    {
2215
2178
      string testdir(opt_testdir);
2216
2179
      if (testdir[testdir.length()] != '/')
2478
2441
                     rm_args, sizeof(rm_args)/sizeof(struct command_arg),
2479
2442
                     ' ');
2480
2443
 
2481
 
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
 
2444
  error= my_delete(ds_filename.c_str(), MYF(0)) != 0;
2482
2445
  handle_command_error(command, error);
2483
2446
  return;
2484
2447
}
2512
2475
                     sizeof(copy_file_args)/sizeof(struct command_arg),
2513
2476
                     ' ');
2514
2477
 
2515
 
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
 
2478
  error= (my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2516
2479
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2517
2480
  handle_command_error(command, error);
2518
2481
  return;
2549
2512
  /* Parse what mode to set */
2550
2513
  istringstream buff(ds_mode);
2551
2514
  if (ds_mode.length() != 4 ||
2552
 
      (buff >> oct >> mode).fail())
 
2515
      (buff >> mode).fail())
2553
2516
    die("You must write a 4 digit octal number for mode");
2554
2517
 
2555
2518
  handle_command_error(command, chmod(ds_file.c_str(), mode));
2610
2573
                     mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg),
2611
2574
                     ' ');
2612
2575
 
2613
 
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
 
2576
  error= mkdir(ds_dirname.c_str(), (0777 & my_umask_dir)) != 0;
2614
2577
  handle_command_error(command, error);
2615
2578
  return;
2616
2579
}
2977
2940
static void do_perl(struct st_command *command)
2978
2941
{
2979
2942
  int error;
2980
 
  int fd;
 
2943
  File fd;
2981
2944
  FILE *res_file;
2982
2945
  char buf[FN_REFLEN];
2983
2946
  char temp_file_path[FN_REFLEN];
3001
2964
  read_until_delimiter(&ds_script, &ds_delimiter);
3002
2965
 
3003
2966
  /* Create temporary file name */
3004
 
  if ((fd= internal::create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
3005
 
                            "tmp", MYF(MY_WME))) < 0)
 
2967
  if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
 
2968
                            "tmp", O_CREAT | O_RDWR,
 
2969
                            MYF(MY_WME))) < 0)
3006
2970
    die("Failed to create temporary file for perl command");
3007
 
  internal::my_close(fd, MYF(0));
 
2971
  my_close(fd, MYF(0));
3008
2972
 
3009
2973
  str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
3010
2974
 
3024
2988
  error= pclose(res_file);
3025
2989
 
3026
2990
  /* Remove the temporary file */
3027
 
  internal::my_delete(temp_file_path, MYF(0));
 
2991
  my_delete(temp_file_path, MYF(0));
3028
2992
 
3029
2993
  handle_command_error(command, WEXITSTATUS(error));
3030
2994
  return;
3130
3094
  if (!master_pos.file[0])
3131
3095
    die("Calling 'sync_with_master' without calling 'save_master_pos'");
3132
3096
 
3133
 
  snprintf(query_buf, sizeof(query_buf), "select master_pos_wait('%s', %ld)", master_pos.file,
 
3097
  sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
3134
3098
          master_pos.pos + offset);
3135
3099
 
3136
3100
wait_for_position:
3317
3281
  bool error= false;
3318
3282
  char *p= command->first_argument;
3319
3283
  char *sleep_start, *sleep_end= command->end;
3320
 
  double sleep_val= 0;
 
3284
  double sleep_val;
3321
3285
 
3322
3286
  while (my_isspace(charset_info, *p))
3323
3287
    p++;
3324
3288
  if (!*p)
3325
3289
    die("Missing argument to %.*s", command->first_word_len, command->query);
3326
3290
  sleep_start= p;
3327
 
  /* Check that arg starts with a digit, not handled by internal::my_strtod */
 
3291
  /* Check that arg starts with a digit, not handled by my_strtod */
3328
3292
  if (!my_isdigit(charset_info, *sleep_start))
3329
3293
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
3330
3294
        command->query,command->first_argument);
3346
3310
}
3347
3311
 
3348
3312
 
3349
 
static void do_get_file_name(struct st_command *command, string &dest)
 
3313
static void do_get_file_name(struct st_command *command,
 
3314
                             char* dest, uint32_t dest_max_len)
3350
3315
{
3351
3316
  char *p= command->first_argument, *name;
3352
3317
  if (!*p)
3357
3322
  if (*p)
3358
3323
    *p++= 0;
3359
3324
  command->last_argument= p;
3360
 
  if (! opt_testdir.empty())
3361
 
  {
3362
 
    dest= opt_testdir;
3363
 
    if (dest[dest.length()] != '/')
3364
 
      dest.append("/");
3365
 
  }
3366
 
  dest.append(name);
 
3325
  strncpy(dest, name, dest_max_len - 1);
3367
3326
}
3368
3327
 
3369
3328
 
3386
3345
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3387
3346
}
3388
3347
 
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
3348
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3449
3349
{
3450
 
  size_t err_name_len= error_end - error_name;
3451
 
  string error_name_s(error_name, err_name_len);
 
3350
  /* SQL error as string */
 
3351
  st_error *e= global_error_names;
3452
3352
 
3453
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3454
 
  if (it != global_error_names.end())
 
3353
  /* Loop through the array of known error names */
 
3354
  for (; e->name; e++)
3455
3355
  {
3456
 
    return (*it).second;
 
3356
    /*
 
3357
      If we get a match, we need to check the length of the name we
 
3358
      matched against in case it was longer than what we are checking
 
3359
      (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT).
 
3360
    */
 
3361
    if (!strncmp(error_name, e->name, (int) (error_end - error_name)) &&
 
3362
        (uint32_t) strlen(e->name) == (uint32_t) (error_end - error_name))
 
3363
    {
 
3364
      return(e->code);
 
3365
    }
3457
3366
  }
3458
 
 
3459
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3460
 
  return 0;
 
3367
  if (!e->name)
 
3368
    die("Unknown SQL error name '%s'", error_name);
 
3369
  return(0);
3461
3370
}
3462
3371
 
3463
3372
static void do_get_errcodes(struct st_command *command)
3755
3664
*/
3756
3665
 
3757
3666
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)
 
3667
                         const char *host, const char *user, const char *pass,
 
3668
                         const char *db, int port)
3760
3669
{
3761
 
  uint32_t failed_attempts= 0;
 
3670
  int failed_attempts= 0;
3762
3671
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
3763
3672
  drizzle_return_t ret;
3764
3673
 
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());
 
3674
  drizzle_con_set_tcp(con, host, port);
 
3675
  drizzle_con_set_auth(con, user, pass);
 
3676
  drizzle_con_set_db(con, db);
3768
3677
  while((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
3769
3678
  {
3770
3679
    /*
3858
3767
  drizzle_con_set_db(con, db);
3859
3768
  if ((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
3860
3769
  {
3861
 
    if (ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
 
3770
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3862
3771
    {
3863
3772
      var_set_errno(drizzle_con_error_code(con));
3864
3773
      handle_error(command, drizzle_con_error_code(con), drizzle_con_error(con),
3906
3815
 
3907
3816
static void do_connect(struct st_command *command)
3908
3817
{
3909
 
  uint32_t con_port= opt_port;
 
3818
  int con_port= opt_port;
3910
3819
  const char *con_options;
3911
 
  bool con_ssl= 0;
 
3820
  bool con_ssl= 0, con_compress= 0;
3912
3821
  struct st_connection* con_slot;
3913
3822
 
3914
3823
  string ds_connection_name;
3954
3863
    if (*ds_sock.c_str() != FN_LIBCHAR)
3955
3864
    {
3956
3865
      char buff[FN_REFLEN];
3957
 
      internal::fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
 
3866
      fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
3958
3867
      ds_sock.clear();
3959
3868
      ds_sock.append(buff);
3960
3869
    }
3974
3883
      end++;
3975
3884
    if (!strncmp(con_options, "SSL", 3))
3976
3885
      con_ssl= 1;
 
3886
    else if (!strncmp(con_options, "COMPRESS", 8))
 
3887
      con_compress= 1;
3977
3888
    else
3978
3889
      die("Illegal option to connect: %.*s",
3979
3890
          (int) (end - con_options), con_options);
3999
3910
    die("Failed on drizzle_create()");
4000
3911
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
4001
3912
    die("Failed on drizzle_con_create()");
4002
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
4003
3913
 
4004
3914
  /* Use default db name */
4005
3915
  if (ds_database.length() == 0)
4140
4050
  if (not_expr)
4141
4051
    cur_block->ok = !cur_block->ok;
4142
4052
 
4143
 
  free(v.str_val);
4144
 
  free(v.env_s);
4145
 
 
 
4053
  var_free(&v);
4146
4054
  return;
4147
4055
}
4148
4056
 
4219
4127
 
4220
4128
*/
4221
4129
 
4222
 
 
4223
 
static int my_strnncoll_simple(const CHARSET_INFO * const  cs, const unsigned char *s, size_t slen,
4224
 
                               const unsigned char *t, size_t tlen,
4225
 
                               bool t_is_prefix)
4226
 
{
4227
 
  size_t len = ( slen > tlen ) ? tlen : slen;
4228
 
  unsigned char *map= cs->sort_order;
4229
 
  if (t_is_prefix && slen > tlen)
4230
 
    slen=tlen;
4231
 
  while (len--)
4232
 
  {
4233
 
    if (map[*s++] != map[*t++])
4234
 
      return ((int) map[s[-1]] - (int) map[t[-1]]);
4235
 
  }
4236
 
  /*
4237
 
    We can't use (slen - tlen) here as the result may be outside of the
4238
 
    precision of a signed int
4239
 
  */
4240
 
  return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
4241
 
}
4242
 
 
4243
4130
static int read_line(char *buf, int size)
4244
4131
{
4245
4132
  char c, last_quote= 0;
4299
4186
      }
4300
4187
      else if ((c == '{' &&
4301
4188
                (!my_strnncoll_simple(charset_info, (const unsigned char*) "while", 5,
4302
 
                                      (unsigned char*) buf, min((ptrdiff_t)5, p - buf), 0) ||
 
4189
                                      (unsigned char*) buf, cmin((long)5, p - buf), 0) ||
4303
4190
                 !my_strnncoll_simple(charset_info, (const unsigned char*) "if", 2,
4304
 
                                      (unsigned char*) buf, min((ptrdiff_t)2, p - buf), 0))))
 
4191
                                      (unsigned char*) buf, cmin((long)2, p - buf), 0))))
4305
4192
      {
4306
4193
        /* Only if and while commands can be terminated by { */
4307
4194
        *p++= c;
4378
4265
    {
4379
4266
      /* Could be a multibyte character */
4380
4267
      /* This code is based on the code in "sql_load.cc" */
 
4268
#ifdef USE_MB
4381
4269
      int charlen = my_mbcharlen(charset_info, c);
4382
4270
      /* We give up if multibyte character is started but not */
4383
4271
      /* completed before we pass buf_end */
4404
4292
        }
4405
4293
      }
4406
4294
      else
 
4295
#endif
4407
4296
        *p++= c;
4408
4297
    }
4409
4298
  }
4563
4452
  return;
4564
4453
}
4565
4454
 
 
4455
 
 
4456
 
4566
4457
/*
4567
4458
  Create a command from a set of lines
4568
4459
 
4580
4471
  terminated by new line '\n' regardless how many "delimiter" it contain.
4581
4472
*/
4582
4473
 
4583
 
#define MAX_QUERY (768*1024*2) /* 256K -- a test in sp-big is >128K */
 
4474
#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */
4584
4475
static char read_command_buf[MAX_QUERY];
4585
4476
 
4586
4477
static int read_command(struct st_command** command_ptr)
4594
4485
    *command_ptr= q_lines[parser.current_line];
4595
4486
    return(0);
4596
4487
  }
4597
 
  if (!(*command_ptr= command= new st_command))
4598
 
    die("command construction failed");
 
4488
  if (!(*command_ptr= command=
 
4489
        (struct st_command*) malloc(sizeof(*command))))
 
4490
    die(NULL);
 
4491
  memset(command, 0, sizeof(*command));
4599
4492
  q_lines.push_back(command);
4600
4493
  command->type= Q_UNKNOWN;
4601
4494
 
4642
4535
  return(0);
4643
4536
}
4644
4537
 
 
4538
 
 
4539
static struct my_option my_long_options[] =
 
4540
{
 
4541
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
4542
   0, 0, 0, 0, 0, 0},
 
4543
  {"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
 
4544
   (char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4545
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
4546
   "Directory where character sets are.", (char**) &opt_charsets_dir,
 
4547
   (char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4548
  {"compress", 'C', "Use the compressed server/client protocol.",
 
4549
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
4550
   0, 0, 0},
 
4551
  {"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
 
4552
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4553
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
4554
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
4555
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4556
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
4557
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
4558
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4559
  {"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
 
4560
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4561
  {"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
 
4562
   (char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4563
  {"testdir", OPT_TESTDIR, "Path to use to search for test files",
 
4564
   (char**) &opt_testdir,
 
4565
   (char**) &opt_testdir, 0,GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4566
  {"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
 
4567
   (char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4568
  {"mark-progress", OPT_MARK_PROGRESS,
 
4569
   "Write linenumber and elapsed time to <testname>.progress ",
 
4570
   (char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
 
4571
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4572
  {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
 
4573
   "Max number of connection attempts when connecting to server",
 
4574
   (char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
 
4575
   GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
 
4576
  {"password", 'P', "Password to use when connecting to server.",
 
4577
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
4578
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
 
4579
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
4580
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
4581
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4582
  {"quiet", 's', "Suppress all normal output.", (char**) &silent,
 
4583
   (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4584
  {"record", 'r', "Record output of test_file into result file.",
 
4585
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4586
  {"result-file", 'R', "Read/Store result from/in this file.",
 
4587
   (char**) &result_file_name, (char**) &result_file_name, 0,
 
4588
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4589
  {"server-arg", 'A', "Send option value to embedded server as a parameter.",
 
4590
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4591
  {"server-file", 'F', "Read embedded server arguments from file.",
 
4592
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4593
  {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
 
4594
   (char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4595
  {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
 
4596
   (char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
 
4597
   0, 0, 0},
 
4598
  {"tail-lines", OPT_TAIL_LINES,
 
4599
   "Number of lines of the resul to include in a failure report",
 
4600
   (char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
 
4601
   GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
 
4602
  {"test-file", 'x', "Read test from/in this file (default stdin).",
 
4603
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4604
  {"timer-file", 'm', "File where the timing in micro seconds is stored.",
 
4605
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4606
  {"tmpdir", 't', "Temporary directory where sockets are put.",
 
4607
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4608
  {"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
 
4609
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4610
  {"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
 
4611
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4612
  {"version", 'V', "Output version information and exit.",
 
4613
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4614
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
4615
};
 
4616
 
 
4617
 
 
4618
static void print_version(void)
 
4619
{
 
4620
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
 
4621
         drizzle_version(),SYSTEM_TYPE,MACHINE_TYPE);
 
4622
}
 
4623
 
 
4624
static void usage(void)
 
4625
{
 
4626
  print_version();
 
4627
  printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
 
4628
  printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
 
4629
  printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
 
4630
  printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
 
4631
  my_print_help(my_long_options);
 
4632
  printf("  --no-defaults       Don't read default options from any options file.\n");
 
4633
  my_print_variables(my_long_options);
 
4634
}
 
4635
 
 
4636
/*
 
4637
  Read arguments for embedded server and put them into
 
4638
  embedded_server_args[]
 
4639
*/
 
4640
 
 
4641
static void read_embedded_server_arguments(const char *name)
 
4642
{
 
4643
  char argument[1024],buff[FN_REFLEN], *str=0;
 
4644
  FILE *file;
 
4645
 
 
4646
  if (!test_if_hard_path(name))
 
4647
  {
 
4648
    sprintf(buff,"%s%s",opt_basedir,name);
 
4649
    name=buff;
 
4650
  }
 
4651
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
4652
 
 
4653
  if (!embedded_server_arg_count)
 
4654
  {
 
4655
    embedded_server_arg_count=1;
 
4656
    embedded_server_args[0]= (char*) "";    /* Progname */
 
4657
  }
 
4658
  if (!(file= fopen(buff, "r")))
 
4659
    die("Failed to open file '%s'", buff);
 
4660
 
 
4661
  while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
 
4662
         (str=fgets(argument,sizeof(argument), file)))
 
4663
  {
 
4664
    *(strchr(str, '\0')-1)=0;        /* Remove end newline */
 
4665
    if (!(embedded_server_args[embedded_server_arg_count]=
 
4666
          (char*) strdup(str)))
 
4667
    {
 
4668
      fclose(file);
 
4669
      die("Out of memory");
 
4670
 
 
4671
    }
 
4672
    embedded_server_arg_count++;
 
4673
  }
 
4674
  fclose(file);
 
4675
  if (str)
 
4676
    die("Too many arguments in option file: %s",name);
 
4677
 
 
4678
  return;
 
4679
}
 
4680
 
 
4681
 
 
4682
extern "C" bool
 
4683
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
 
4645
4816
/*
4646
4817
  Write the content of str into file
4647
4818
 
4658
4829
  int fd;
4659
4830
  char buff[FN_REFLEN];
4660
4831
  int flags= O_WRONLY | O_CREAT;
4661
 
  if (!internal::test_if_hard_path(fname))
 
4832
  if (!test_if_hard_path(fname))
4662
4833
  {
4663
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
 
4834
    sprintf(buff,"%s%s",opt_basedir,fname);
4664
4835
    fname= buff;
4665
4836
  }
4666
 
  internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
 
4837
  fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4667
4838
 
4668
4839
  if (!append)
4669
4840
    flags|= O_TRUNC;
4670
 
  if ((fd= internal::my_open(buff, flags,
 
4841
  if ((fd= my_open(buff, flags,
4671
4842
                   MYF(MY_WME | MY_FFNF))) < 0)
4672
4843
    die("Could not open '%s' for writing: errno = %d", buff, errno);
4673
4844
  if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
4674
4845
    die("Could not find end of file '%s': errno = %d", buff, errno);
4675
 
  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)))
4676
4847
    die("write failed");
4677
 
  internal::my_close(fd, MYF(0));
 
4848
  my_close(fd, MYF(0));
4678
4849
}
4679
4850
 
4680
4851
/*
4696
4867
void dump_result_to_log_file(const char *buf, int size)
4697
4868
{
4698
4869
  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 :
 
4870
  str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log",
 
4871
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4701
4872
                        MY_REPLACE_EXT),
4702
4873
              buf, size);
4703
4874
  fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
4707
4878
void dump_progress(void)
4708
4879
{
4709
4880
  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 :
 
4881
  str_to_file(fn_format(progress_file, result_file_name,
 
4882
                        opt_logdir, ".progress",
 
4883
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4713
4884
                        MY_REPLACE_EXT),
4714
4885
              ds_progress.c_str(), ds_progress.length());
4715
4886
}
4718
4889
{
4719
4890
  char warn_file[FN_REFLEN];
4720
4891
 
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 :
 
4892
  str_to_file(fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
 
4893
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4723
4894
                        MY_REPLACE_EXT),
4724
4895
              ds_warning_messages.c_str(), ds_warning_messages.length());
4725
4896
}
4948
5119
    (void) drizzle_query(con, &res, query, query_len, &ret);
4949
5120
    if (ret != DRIZZLE_RETURN_OK)
4950
5121
    {
4951
 
      if (ret == DRIZZLE_RETURN_ERROR_CODE ||
4952
 
          ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
 
5122
      if (ret == DRIZZLE_RETURN_ERROR_CODE)
4953
5123
      {
4954
5124
        err= drizzle_result_error_code(&res);
4955
5125
        handle_error(command, err, drizzle_result_error(&res),
4956
5126
                     drizzle_result_sqlstate(&res), ds);
4957
 
        if (ret == DRIZZLE_RETURN_ERROR_CODE)
4958
 
          drizzle_result_free(&res);
 
5127
        drizzle_result_free(&res);
4959
5128
      }
4960
5129
      else
4961
5130
      {
5023
5192
      }
5024
5193
 
5025
5194
      /*
5026
 
        Need to call drizzle_result_affected_rows() before the "new"
 
5195
        Need to call drizzleclient_affected_rows() before the "new"
5027
5196
        query to find the warnings
5028
5197
      */
5029
5198
      if (!disable_info)
5090
5259
  uint32_t i;
5091
5260
 
5092
5261
 
5093
 
  if (! command->require_file.empty())
 
5262
  if (command->require_file[0])
5094
5263
  {
5095
5264
    /*
5096
5265
      The query after a "--require" failed. This is fine as long the server
5249
5418
    Create a temporary dynamic string to contain the output from
5250
5419
    this query.
5251
5420
  */
5252
 
  if (! command->require_file.empty())
 
5421
  if (command->require_file[0])
5253
5422
  {
5254
5423
    ds= &ds_result;
5255
5424
  }
5292
5461
    ds= save_ds;
5293
5462
  }
5294
5463
 
5295
 
  if (! command->require_file.empty())
 
5464
  if (command->require_file[0])
5296
5465
  {
5297
5466
    /* A result file was specified for _this_ query
5298
5467
       and the output should be checked against an already
5417
5586
 
5418
5587
}
5419
5588
 
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
5589
 
5450
5590
int main(int argc, char **argv)
5451
5591
{
5452
 
try
5453
 
{
5454
5592
  struct st_command *command;
5455
5593
  bool q_send_flag= 0, abort_flag= 0;
5456
5594
  uint32_t command_executed= 0, last_command_executed= 0;
5457
 
  string save_file("");
 
5595
  char save_file[FN_REFLEN];
5458
5596
  struct stat res_info;
 
5597
  MY_INIT(argv[0]);
5459
5598
 
 
5599
  save_file[0]= 0;
5460
5600
  TMPDIR[0]= 0;
5461
5601
 
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
5602
  /* Init expected errors */
5581
5603
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5582
5604
 
5600
5622
  cur_block->ok= true; /* Outer block should always be executed */
5601
5623
  cur_block->cmd= cmd_none;
5602
5624
 
 
5625
  if (hash_init(&var_hash, charset_info,
 
5626
                1024, 0, 0, get_var_key, var_free, MYF(0)))
 
5627
    die("Variable hash initialization failed");
 
5628
 
5603
5629
  var_set_string("$DRIZZLE_SERVER_VERSION", drizzle_version());
5604
5630
 
5605
5631
  memset(&master_pos, 0, sizeof(master_pos));
5613
5639
  ds_progress.reserve(2048);
5614
5640
  ds_warning_messages.reserve(2048);
5615
5641
 
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
 
  }
 
5642
  parse_args(argc, argv);
5735
5643
 
5736
5644
  server_initialized= 1;
5737
5645
  if (cur_file == file_stack && cur_file->file == 0)
5747
5655
    die("Failed in drizzle_create()");
5748
5656
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5749
5657
    die("Failed in drizzle_con_create()");
5750
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
5751
5658
 
5752
5659
  if (!(cur_con->name = strdup("default")))
5753
5660
    die("Out of memory");
 
5661
 
5754
5662
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5755
5663
               opt_db, opt_port);
5756
5664
 
5757
 
  fill_global_error_names();
5758
 
 
5759
5665
  /* Use all time until exit if no explicit 'start_timer' */
5760
5666
  timer_start= timer_now();
5761
5667
 
5769
5675
  /* Update $drizzleclient_get_server_version to that of current connection */
5770
5676
  var_set_drizzleclient_get_server_version(&cur_con->con);
5771
5677
 
5772
 
  if (! opt_include.empty())
 
5678
  if (opt_include)
5773
5679
  {
5774
 
    open_file(opt_include.c_str());
 
5680
    open_file(opt_include);
5775
5681
  }
5776
5682
 
5777
5683
  while (!read_command(&command) && !abort_flag)
5885
5791
        /* Check for special property for this query */
5886
5792
        display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
5887
5793
 
5888
 
        if (! save_file.empty())
 
5794
        if (save_file[0])
5889
5795
        {
5890
 
          command->require_file= save_file;
5891
 
          save_file.clear();
 
5796
          strncpy(command->require_file, save_file, sizeof(save_file) - 1);
 
5797
          save_file[0]= 0;
5892
5798
        }
5893
5799
        run_query(cur_con, command, flags);
5894
5800
        command_executed++;
5925
5831
        command->last_argument= command->end;
5926
5832
        break;
5927
5833
      case Q_REQUIRE:
5928
 
        do_get_file_name(command, save_file);
 
5834
        do_get_file_name(command, save_file, sizeof(save_file));
5929
5835
        break;
5930
5836
      case Q_ERROR:
5931
5837
        do_get_errcodes(command);
6075
5981
  */
6076
5982
  if (ds_res.length())
6077
5983
  {
6078
 
    if (! result_file_name.empty())
 
5984
    if (result_file_name)
6079
5985
    {
6080
5986
      /* A result file has been specified */
6081
5987
 
6082
5988
      if (record)
6083
5989
      {
6084
5990
        /* 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());
 
5991
        str_to_file(result_file_name, ds_res.c_str(), ds_res.length());
6086
5992
      }
6087
5993
      else
6088
5994
      {
6105
6011
  }
6106
6012
 
6107
6013
  if (!command_executed &&
6108
 
      ! result_file_name.empty() && !stat(result_file_name.c_str(), &res_info))
 
6014
      result_file_name && !stat(result_file_name, &res_info))
6109
6015
  {
6110
6016
    /*
6111
6017
      my_stat() successful on result file. Check if we have not run a
6117
6023
    die("No queries executed but result file found!");
6118
6024
  }
6119
6025
 
6120
 
  if ( opt_mark_progress && ! result_file_name.empty() )
 
6026
  if ( opt_mark_progress && result_file_name )
6121
6027
    dump_progress();
6122
6028
 
6123
6029
  /* Dump warning messages */
6124
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
6030
  if (result_file_name && ds_warning_messages.length())
6125
6031
    dump_warning_messages();
6126
6032
 
6127
6033
  timer_output();
6128
6034
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
6129
6035
  cleanup_and_exit(0);
6130
 
}
6131
 
 
6132
 
  catch(exception &err)
6133
 
  {
6134
 
    cerr<<err.what()<<endl;
6135
 
  }
6136
 
 
6137
6036
  return 0; /* Keep compiler happy too */
6138
6037
}
6139
6038
 
6175
6074
 
6176
6075
uint64_t timer_now(void)
6177
6076
{
6178
 
#if defined(HAVE_GETHRTIME)
6179
 
  return gethrtime()/1000/1000;
6180
 
#else
6181
 
  uint64_t newtime;
6182
 
  struct timeval t;
6183
 
  /*
6184
 
    The following loop is here because gettimeofday may fail on some systems
6185
 
  */
6186
 
  while (gettimeofday(&t, NULL) != 0)
6187
 
  {}
6188
 
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
6189
 
  return newtime/1000;
6190
 
#endif  /* defined(HAVE_GETHRTIME) */
 
6077
  return my_micro_time() / 1000;
6191
6078
}
6192
6079
 
6193
6080
 
6402
6289
  char* pattern; /* Pattern to be replaced */
6403
6290
  char* replace; /* String or expression to replace the pattern with */
6404
6291
  int icase; /* true if the match is case insensitive */
6405
 
  int global; /* true if the match should be global -- 
6406
 
                 i.e. repeat the matching until the end of the string */
6407
6292
};
6408
6293
 
6409
6294
struct st_replace_regex
6427
6312
struct st_replace_regex *glob_replace_regex= 0;
6428
6313
 
6429
6314
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6430
 
                char *string, int icase, int global);
 
6315
                char *string, int icase);
6431
6316
 
6432
6317
 
6433
6318
 
6528
6413
 
6529
6414
    /* Check if we should do matching case insensitive */
6530
6415
    if (p < expr_end && *p == 'i')
6531
 
    {
6532
 
      p++;
6533
6416
      reg.icase= 1;
6534
 
    }
6535
 
 
6536
 
    /* Check if we should do matching globally */
6537
 
    if (p < expr_end && *p == 'g')
6538
 
    {
6539
 
      p++;
6540
 
      reg.global= 1;
6541
 
    }
6542
6417
 
6543
6418
    /* done parsing the statement, now place it in regex_arr */
6544
6419
    if (insert_dynamic(&res->regex_arr,(unsigned char*) &reg))
6596
6471
    get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
6597
6472
 
6598
6473
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
6599
 
                     in_buf, re.icase, re.global))
 
6474
                     in_buf, re.icase))
6600
6475
    {
6601
6476
      /* if the buffer has been reallocated, make adjustements */
6602
6477
      if (save_out_buf != out_buf)
6666
6541
  icase - flag, if set to 1 the match is case insensitive
6667
6542
*/
6668
6543
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
6669
 
                char *replace, char *in_string, int icase, int global)
 
6544
                char *replace, char *in_string, int icase)
6670
6545
{
 
6546
  string string_to_match(in_string);
6671
6547
  const char *error= NULL;
6672
6548
  int erroffset;
6673
6549
  int ovector[3];
6674
6550
  pcre *re= pcre_compile(pattern,
6675
 
                         icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
 
6551
                         icase ? PCRE_CASELESS : 0,
6676
6552
                         &error, &erroffset, NULL);
6677
6553
  if (re == NULL)
6678
6554
    return 1;
6679
6555
 
6680
 
  if (! global)
6681
 
  {
6682
 
 
6683
 
    int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6684
 
                      0, 0, ovector, 3);
6685
 
    if (rc < 0)
6686
 
    {
6687
 
      pcre_free(re);
6688
 
      return 1;
6689
 
    }
6690
 
 
6691
 
    char *substring_to_replace= in_string + ovector[0];
6692
 
    int substring_length= ovector[1] - ovector[0];
6693
 
    *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6694
 
    char * new_buf = (char *)malloc(*buf_len_p+1);
6695
 
    if (new_buf == NULL)
6696
 
    {
6697
 
      pcre_free(re);
6698
 
      return 1;
6699
 
    }
6700
 
 
6701
 
    memset(new_buf, 0, *buf_len_p+1);
6702
 
    strncpy(new_buf, in_string, substring_to_replace-in_string);
6703
 
    strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6704
 
    strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6705
 
            substring_to_replace + substring_length,
6706
 
            strlen(in_string)
6707
 
              - substring_length
6708
 
              - (substring_to_replace-in_string));
6709
 
    *buf_p= new_buf;
6710
 
 
6711
 
    pcre_free(re);
6712
 
    return 0;
6713
 
  }
6714
 
  else
6715
 
  {
6716
 
    /* Repeatedly replace the string with the matched regex */
6717
 
    string subject(in_string);
6718
 
    size_t replace_length= strlen(replace);
6719
 
    size_t length_of_replacement= strlen(replace);
6720
 
    size_t current_position= 0;
6721
 
    int rc= 0;
6722
 
 
6723
 
    while (true) 
6724
 
    {
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
 
      current_position= static_cast<size_t>(ovector[0]);
6733
 
      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;
6736
 
    }
6737
 
 
6738
 
    char *new_buf = (char *) malloc(subject.length() + 1);
6739
 
    if (new_buf == NULL)
6740
 
    {
6741
 
      pcre_free(re);
6742
 
      return 1;
6743
 
    }
6744
 
    memset(new_buf, 0, subject.length() + 1);
6745
 
    strncpy(new_buf, subject.c_str(), subject.length());
6746
 
    *buf_len_p= subject.length() + 1;
6747
 
    *buf_p= new_buf;
6748
 
          
6749
 
    pcre_free(re);
6750
 
    return 0;
6751
 
  }
 
6556
  int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
 
6557
                    0, 0, ovector, 3);
 
6558
  if (rc < 0)
 
6559
  {
 
6560
    pcre_free(re);
 
6561
    return 1;
 
6562
  }
 
6563
 
 
6564
  char *substring_to_replace= in_string + ovector[0];
 
6565
  int substring_length= ovector[1] - ovector[0];
 
6566
  *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
 
6567
  char * new_buf = (char *)malloc(*buf_len_p+1);
 
6568
  if (new_buf == NULL)
 
6569
  {
 
6570
    pcre_free(re);
 
6571
    return 1;
 
6572
  }
 
6573
 
 
6574
  memset(new_buf, 0, *buf_len_p+1);
 
6575
  strncpy(new_buf, in_string, substring_to_replace-in_string);
 
6576
  strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
 
6577
  strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
 
6578
          substring_to_replace + substring_length,
 
6579
          strlen(in_string)
 
6580
            - substring_length
 
6581
            - (substring_to_replace-in_string));
 
6582
  *buf_p= new_buf;
 
6583
 
 
6584
  pcre_free(re);
 
6585
  return 0;
6752
6586
}
6753
6587
 
6754
6588
 
7332
7166
      return(1);
7333
7167
    if (new_pos != pa->str)
7334
7168
    {
7335
 
      ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
 
7169
      my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
7336
7170
      for (i=0 ; i < pa->typelib.count ; i++)
7337
7171
        pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
7338
7172
                                              char*);