~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

* Fixes drizzled's atomics:

- fetch_and_add() was actually add_and_fetch() - fixed to have both methods correct
- compare_and_swap() was incorrect for all traits classes.  Fixed to return a bool
true only when the supplied value is actually swapped
- fixes increment() and decrement() methods and operator+=() in outer atomics class
template to call proper add_and_fetch() methods on traits classes
- Now that above are fixed, removed the hacks in Query_id and TransactionLog to
have query ID and the new transactoin ID start properly at 1.

* Transaction messages sent over replication stream now use
a real transaction ID, managed by drizzled::TransactionServices.  Previously, 
the Query_id was being used, resulting in SELECT statements incrementing the
transaction ID.

* Added a test case to ensure that DDL ops are given a transaction ID and SELECT
ops do not increment the transaction ID.

The transaction ID will be paired with a channel ID to become the global
transaction identifier.  ReplicationServices will manage the pairing of
channel and transaction ID and understand how far a particular subscriber
node has applied.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 * 
4
 
 *  Copyright (C) 2010 Vijay Samuel
 
3
 *
5
4
 *  Copyright (C) 2008 MySQL
6
5
 *
7
6
 *  This program is free software; you can redistribute it and/or modify
45
44
#include <map>
46
45
#include <string>
47
46
#include <sstream>
48
 
#include <fstream>
49
47
#include <iostream>
50
48
#include <vector>
51
49
#include <algorithm>
56
54
#include <sys/stat.h>
57
55
#include <sys/types.h>
58
56
#include <fcntl.h>
59
 
#include <boost/array.hpp>
60
 
#include <boost/foreach.hpp>
61
 
#include <boost/program_options.hpp>
62
 
#include <boost/smart_ptr.hpp>
63
57
 
64
58
#include PCRE_HEADER
65
59
 
66
60
#include <stdarg.h>
67
 
#include <boost/unordered_map.hpp>
 
61
 
 
62
#include "errname.h"
68
63
 
69
64
/* Added this for string translation. */
70
 
#include <drizzled/gettext.h>
71
 
#include <drizzled/type/time.h>
72
 
#include <drizzled/charset.h>
73
 
#include <drizzled/typelib.h>
74
 
#include <drizzled/configmake.h>
75
 
 
76
 
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
 
65
#include "drizzled/gettext.h"
 
66
#include "drizzled/hash.h"
 
67
#include "drizzled/my_time.h"
 
68
#include "drizzled/charset.h"
77
69
 
78
70
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
71
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
80
72
#endif
81
 
namespace po= boost::program_options;
 
73
 
82
74
using namespace std;
83
75
using namespace drizzled;
84
76
 
85
77
extern "C"
86
78
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
87
79
 
88
 
int get_one_option(int optid, const struct option *, char *argument);
 
80
int get_one_option(int optid, const struct my_option *, char *argument);
89
81
 
90
82
#define MAX_VAR_NAME_LENGTH    256
91
83
#define MAX_COLUMNS            256
94
86
#define QUERY_SEND_FLAG  1
95
87
#define QUERY_REAP_FLAG  2
96
88
 
97
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
98
89
ErrorCodes global_error_names;
99
90
 
100
91
enum {
104
95
};
105
96
 
106
97
static int record= 0, opt_sleep= -1;
107
 
static char *opt_pass= NULL;
108
 
const char *unix_sock= NULL;
 
98
static char *opt_db= NULL, *opt_pass= NULL;
 
99
const char *opt_user= NULL, *opt_host= NULL, *unix_sock= NULL,
 
100
           *opt_basedir= "./";
 
101
const char *opt_logdir= "";
 
102
const char *opt_include= NULL, *opt_charsets_dir;
 
103
const char *opt_testdir= NULL;
109
104
static uint32_t opt_port= 0;
110
 
static uint32_t opt_max_connect_retries;
 
105
static int opt_max_connect_retries;
111
106
static bool silent= false, verbose= false;
 
107
static bool tty_password= false;
112
108
static bool opt_mark_progress= false;
113
109
static bool parsing_disabled= false;
114
110
static bool display_result_vertically= false,
119
115
static bool abort_on_error= true;
120
116
static bool server_initialized= false;
121
117
static bool is_windows= false;
122
 
static bool use_drizzle_protocol= false;
 
118
static bool opt_mysql= false;
 
119
static char **default_argv;
 
120
static const char *load_default_groups[]= { "drizzletest", "client", 0 };
123
121
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
124
 
static void free_all_replace();
125
 
 
126
 
std::string opt_basedir,
127
 
  opt_charsets_dir,
128
 
  opt_db,
129
 
  opt_host,
130
 
  opt_include,
131
 
  opt_testdir,
132
 
  opt_logdir,
133
 
  password,
134
 
  opt_password,
135
 
  result_file_name,
136
 
  opt_user,
137
 
  opt_protocol;
138
122
 
139
123
static uint32_t start_lineno= 0; /* Start line of current command */
140
124
 
171
155
  uint32_t lineno; /* Current line in file */
172
156
};
173
157
 
174
 
static boost::array<st_test_file, 16> file_stack;
175
 
static st_test_file* cur_file;
 
158
static struct st_test_file file_stack[16];
 
159
static struct st_test_file* cur_file;
 
160
static struct st_test_file* file_stack_end;
 
161
 
176
162
 
177
163
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
178
164
 
182
168
*/
183
169
static char *timer_file = NULL;
184
170
static uint64_t timer_start;
185
 
static void timer_output();
186
 
static uint64_t timer_now();
 
171
static void timer_output(void);
 
172
static uint64_t timer_now(void);
187
173
 
188
174
static uint64_t progress_start= 0;
189
175
 
203
189
master_pos_st master_pos;
204
190
 
205
191
/* if set, all results are concated and compared against this file */
 
192
const char *result_file_name= NULL;
206
193
 
207
 
class VAR
 
194
typedef struct st_var
208
195
{
209
 
public:
210
196
  char *name;
211
197
  int name_len;
212
198
  char *str_val;
216
202
  int int_dirty; /* do not update string if int is updated until first read */
217
203
  int alloced;
218
204
  char *env_s;
219
 
};
 
205
} VAR;
220
206
 
221
207
/*Perl/shell-like variable registers */
222
 
boost::array<VAR, 10> var_reg;
223
 
 
224
 
typedef boost::unordered_map<string, VAR *> var_hash_t;
225
 
var_hash_t var_hash;
 
208
VAR var_reg[10];
 
209
 
 
210
 
 
211
drizzled::hash_map<string, VAR *> var_hash;
226
212
 
227
213
struct st_connection
228
214
{
395
381
  struct st_match_err err[10];
396
382
  uint32_t count;
397
383
};
398
 
 
399
 
static st_expected_errors saved_expected_errors;
400
 
 
401
 
class st_command
 
384
static struct st_expected_errors saved_expected_errors;
 
385
 
 
386
struct st_command
402
387
{
403
 
public:
404
388
  char *query, *query_buf,*first_argument,*last_argument,*end;
405
389
  int first_word_len, query_len;
406
390
  bool abort_on_error;
407
391
  st_expected_errors expected_errors;
408
392
  string require_file;
409
 
  enum_commands type;
 
393
  enum enum_commands type;
410
394
 
411
395
  st_command()
412
396
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
418
402
 
419
403
  ~st_command()
420
404
  {
421
 
    free(query_buf);
 
405
    if (query_buf != NULL)
 
406
    {
 
407
      free(query_buf);
 
408
    }
422
409
  }
423
410
};
424
411
 
443
430
VAR* var_from_env(const char *, const char *);
444
431
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
445
432
              int val_len);
 
433
void var_free(pair<string, VAR*> v);
446
434
VAR* var_get(const char *var_name, const char** var_name_end,
447
435
             bool raw, bool ignore_not_existing);
448
436
void eval_expr(VAR* v, const char *p, const char** p_end);
449
437
bool match_delimiter(int c, const char *delim, uint32_t length);
450
438
void dump_result_to_reject_file(char *buf, int size);
451
439
void dump_result_to_log_file(const char *buf, int size);
452
 
void dump_warning_messages();
453
 
void dump_progress();
 
440
void dump_warning_messages(void);
 
441
void dump_progress(void);
454
442
 
455
443
void do_eval(string *query_eval, const char *query,
456
444
             const char *query_end, bool pass_through_escape_chars);
461
449
static char *replace_column[MAX_COLUMNS];
462
450
static uint32_t max_replace_column= 0;
463
451
void do_get_replace_column(struct st_command*);
464
 
void free_replace_column();
 
452
void free_replace_column(void);
465
453
 
466
454
/* For replace */
467
455
void do_get_replace(struct st_command *command);
468
 
void free_replace();
 
456
void free_replace(void);
469
457
 
470
458
/* For replace_regex */
471
459
void do_get_replace_regex(struct st_command *command);
 
460
void free_replace_regex(void);
 
461
 
 
462
 
 
463
void free_all_replace(void);
 
464
 
 
465
 
 
466
void free_all_replace(void){
 
467
  free_replace();
 
468
  free_replace_regex();
 
469
  free_replace_column();
 
470
}
472
471
 
473
472
void replace_append_mem(string *ds, const char *val,
474
473
                        int len);
485
484
void do_eval(string *query_eval, const char *query,
486
485
             const char *query_end, bool pass_through_escape_chars)
487
486
{
488
 
  char c, next_c;
489
 
  int escaped = 0;
 
487
  const char *p;
 
488
  register char c, next_c;
 
489
  register int escaped = 0;
490
490
  VAR *v;
491
491
 
492
 
  for (const char *p= query; (c= *p) && p < query_end; ++p)
 
492
 
 
493
  for (p= query; (c= *p) && p < query_end; ++p)
493
494
  {
494
495
    switch(c) {
495
496
    case '$':
773
774
    const struct command_arg *arg= &args[i];
774
775
    arg->ds->clear();
775
776
 
776
 
    bool known_arg_type= true;
777
777
    switch (arg->type) {
778
778
      /* A string */
779
779
    case ARG_STRING:
808
808
      break;
809
809
 
810
810
    default:
811
 
      known_arg_type= false;
 
811
      assert("Unknown argument type");
812
812
      break;
813
813
    }
814
 
    assert(known_arg_type);
815
814
 
816
815
    /* Check required arg */
817
816
    if (arg->ds->length() == 0 && arg->required)
834
833
 
835
834
static void handle_command_error(struct st_command *command, uint32_t error)
836
835
{
 
836
 
837
837
  if (error != 0)
838
838
  {
839
839
    uint32_t i;
860
860
        command->first_word_len, command->query,
861
861
        command->expected_errors.err[0].code.errnum);
862
862
  }
 
863
  return;
863
864
}
864
865
 
865
866
 
866
 
static void close_connections()
 
867
static void close_connections(void)
867
868
{
868
869
  for (--next_con; next_con >= connections; --next_con)
869
870
  {
874
875
    }
875
876
    free(next_con->name);
876
877
  }
 
878
  return;
877
879
}
878
880
 
879
881
 
880
 
static void close_files()
 
882
static void close_files(void)
881
883
{
882
 
  for (; cur_file >= file_stack.data(); cur_file--)
 
884
 
 
885
  for (; cur_file >= file_stack; cur_file--)
883
886
  {
884
887
    if (cur_file->file && cur_file->file != stdin)
 
888
    {
885
889
      fclose(cur_file->file);
886
 
    free(const_cast<char*>(cur_file->file_name));
 
890
    }
 
891
    free((unsigned char*) cur_file->file_name);
887
892
    cur_file->file_name= 0;
888
893
  }
 
894
  return;
889
895
}
890
896
 
891
 
static void free_used_memory()
 
897
 
 
898
static void free_used_memory(void)
892
899
{
 
900
  uint32_t i;
 
901
 
 
902
 
893
903
  close_connections();
894
904
  close_files();
895
 
  BOOST_FOREACH(var_hash_t::reference i, var_hash)
896
 
  {
897
 
    free(i.second->str_val);
898
 
    free(i.second->env_s);
899
 
    if (i.second->alloced)
900
 
      free(i.second);
901
 
  }
 
905
  for_each(var_hash.begin(), var_hash.end(), var_free);
902
906
  var_hash.clear();
903
 
  BOOST_FOREACH(vector<st_command*>::reference i, q_lines)
904
 
    delete i;
905
 
  for (size_t i= 0; i < var_reg.size(); i++)
 
907
 
 
908
  vector<st_command *>::iterator iter;
 
909
  for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
 
910
  {
 
911
    struct st_command * q_line= *iter;
 
912
    delete q_line;
 
913
  }
 
914
 
 
915
  for (i= 0; i < 10; i++)
906
916
  {
907
917
    if (var_reg[i].alloced_len)
908
918
      free(var_reg[i].str_val);
909
919
  }
 
920
 
910
921
  free_all_replace();
911
922
  free(opt_pass);
 
923
  internal::free_defaults(default_argv);
 
924
 
 
925
  return;
912
926
}
913
927
 
914
928
 
933
947
      assert(0);
934
948
    }
935
949
  }
 
950
 
936
951
  exit(exit_code);
937
952
}
938
953
 
952
967
 
953
968
  /* Print the error message */
954
969
  fprintf(stderr, "drizzletest: ");
955
 
  if (cur_file && cur_file != file_stack.data())
 
970
  if (cur_file && cur_file != file_stack)
956
971
    fprintf(stderr, "In included file \"%s\": ",
957
972
            cur_file->file_name);
958
973
  if (start_lineno > 0)
987
1002
  }
988
1003
 
989
1004
  /* Dump the result that has been accumulated so far to .log file */
990
 
  if (! result_file_name.empty() && ds_res.length())
 
1005
  if (result_file_name && ds_res.length())
991
1006
    dump_result_to_log_file(ds_res.c_str(), ds_res.length());
992
1007
 
993
1008
  /* Dump warning messages */
994
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
1009
  if (result_file_name && ds_warning_messages.length())
995
1010
    dump_warning_messages();
996
1011
 
997
1012
  /*
1013
1028
 
1014
1029
  /* Print include filestack */
1015
1030
  fprintf(stderr, "The test '%s' is not supported by this installation\n",
1016
 
          file_stack[0].file_name);
 
1031
          file_stack->file_name);
1017
1032
  fprintf(stderr, "Detected in file %s at line %d\n",
1018
1033
          err_file->file_name, err_file->lineno);
1019
 
  while (err_file != file_stack.data())
 
1034
  while (err_file != file_stack)
1020
1035
  {
1021
1036
    err_file--;
1022
1037
    fprintf(stderr, "included from %s at line %d\n",
1047
1062
 
1048
1063
  va_start(args, fmt);
1049
1064
  fprintf(stderr, "drizzletest: ");
1050
 
  if (cur_file && cur_file != file_stack.data())
 
1065
  if (cur_file && cur_file != file_stack)
1051
1066
    fprintf(stderr, "In included file \"%s\": ",
1052
1067
            cur_file->file_name);
1053
1068
  if (start_lineno != 0)
1055
1070
  vfprintf(stderr, fmt, args);
1056
1071
  fprintf(stderr, "\n");
1057
1072
  va_end(args);
 
1073
 
 
1074
  return;
1058
1075
}
1059
1076
 
1060
1077
 
1070
1087
  if (start_lineno != 0)
1071
1088
  {
1072
1089
    ds_warning_messages.append("Warning detected ");
1073
 
    if (cur_file && cur_file != file_stack.data())
 
1090
    if (cur_file && cur_file != file_stack)
1074
1091
    {
1075
1092
      len= snprintf(buff, sizeof(buff), "in included file %s ",
1076
1093
                    cur_file->file_name);
1337
1354
  if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1338
1355
  {
1339
1356
    internal::my_close(fd, MYF(0));
1340
 
    if (! opt_testdir.empty())
 
1357
    if (opt_testdir != NULL)
1341
1358
    {
1342
1359
      tmpfile= opt_testdir;
1343
1360
      if (tmpfile[tmpfile.length()] != '/')
1435
1452
  int fd;
1436
1453
  char temp_file_path[FN_REFLEN];
1437
1454
 
1438
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
 
1455
  if ((fd= internal::create_temp_file(temp_file_path, NULL,
1439
1456
                            "tmp", MYF(MY_WME))) < 0)
1440
1457
    die("Failed to create temporary file for ds");
1441
1458
 
1477
1494
  const char* mess= "Result content mismatch\n";
1478
1495
 
1479
1496
 
1480
 
  assert(result_file_name.c_str());
1481
 
 
1482
 
  if (access(result_file_name.c_str(), F_OK) != 0)
1483
 
    die("The specified result file does not exist: '%s'", result_file_name.c_str());
1484
 
 
1485
 
  switch (string_cmp(ds, result_file_name.c_str())) {
 
1497
  assert(result_file_name);
 
1498
 
 
1499
  if (access(result_file_name, F_OK) != 0)
 
1500
    die("The specified result file does not exist: '%s'", result_file_name);
 
1501
 
 
1502
  switch (string_cmp(ds, result_file_name)) {
1486
1503
  case RESULT_OK:
1487
1504
    break; /* ok */
1488
1505
  case RESULT_LENGTH_MISMATCH:
1496
1513
    */
1497
1514
    char reject_file[FN_REFLEN];
1498
1515
    size_t reject_length;
1499
 
    internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
 
1516
    internal::dirname_part(reject_file, result_file_name, &reject_length);
1500
1517
 
1501
1518
    if (access(reject_file, W_OK) == 0)
1502
1519
    {
1503
1520
      /* Result file directory is writable, save reject file there */
1504
 
      internal::fn_format(reject_file, result_file_name.c_str(), NULL,
 
1521
      internal::fn_format(reject_file, result_file_name, NULL,
1505
1522
                ".reject", MY_REPLACE_EXT);
1506
1523
    }
1507
1524
    else
1508
1525
    {
1509
1526
      /* Put reject file in opt_logdir */
1510
 
      internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
 
1527
      internal::fn_format(reject_file, result_file_name, opt_logdir,
1511
1528
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1512
1529
    }
1513
1530
    str_to_file(reject_file, ds->c_str(), ds->length());
1514
1531
 
1515
1532
    ds->erase(); /* Don't create a .log file */
1516
1533
 
1517
 
    show_diff(NULL, result_file_name.c_str(), reject_file);
 
1534
    show_diff(NULL, result_file_name, reject_file);
1518
1535
    die("%s",mess);
1519
1536
    break;
1520
1537
  }
1603
1620
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1604
1621
              int val_len)
1605
1622
{
 
1623
  int val_alloc_len;
 
1624
  VAR *tmp_var;
1606
1625
  if (!name_len && name)
1607
1626
    name_len = strlen(name);
1608
1627
  if (!val_len && val)
1609
1628
    val_len = strlen(val) ;
1610
 
  VAR *tmp_var = v ? v : (VAR*)malloc(sizeof(*tmp_var) + name_len+1);
 
1629
  val_alloc_len = val_len + 16; /* room to grow */
 
1630
  if (!(tmp_var=v) && !(tmp_var = (VAR*)malloc(sizeof(*tmp_var)
 
1631
                                               + name_len+1)))
 
1632
    die("Out of memory");
1611
1633
 
1612
 
  tmp_var->name = name ? (char*)&tmp_var[1] : 0;
 
1634
  tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
1613
1635
  tmp_var->alloced = (v == 0);
1614
1636
 
1615
 
  int val_alloc_len = val_len + 16; /* room to grow */
1616
 
  tmp_var->str_val = (char*)malloc(val_alloc_len+1);
 
1637
  if (!(tmp_var->str_val = (char *)malloc(val_alloc_len+1)))
 
1638
    die("Out of memory");
1617
1639
 
1618
1640
  memcpy(tmp_var->name, name, name_len);
1619
1641
  if (val)
1624
1646
  tmp_var->name_len = name_len;
1625
1647
  tmp_var->str_val_len = val_len;
1626
1648
  tmp_var->alloced_len = val_alloc_len;
1627
 
  tmp_var->int_val = val ? atoi(val) : 0;
1628
 
  tmp_var->int_dirty = false;
 
1649
  tmp_var->int_val = (val) ? atoi(val) : 0;
 
1650
  tmp_var->int_dirty = 0;
1629
1651
  tmp_var->env_s = 0;
1630
1652
  return tmp_var;
1631
1653
}
1632
1654
 
 
1655
 
 
1656
void var_free(pair<string, VAR *> v)
 
1657
{
 
1658
  free(v.second->str_val);
 
1659
  free(v.second->env_s);
 
1660
  if (v.second->alloced)
 
1661
    free(v.second);
 
1662
}
 
1663
 
 
1664
 
1633
1665
VAR* var_from_env(const char *name, const char *def_val)
1634
1666
{
1635
 
  const char *tmp= getenv(name);
1636
 
  if (!tmp)
 
1667
  const char *tmp;
 
1668
  VAR *v;
 
1669
  if (!(tmp = getenv(name)))
1637
1670
    tmp = def_val;
1638
 
  return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1671
 
 
1672
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1673
  string var_name(name);
 
1674
  var_hash.insert(make_pair(var_name, v));
 
1675
  return v;
1639
1676
}
1640
1677
 
 
1678
 
1641
1679
VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
1642
1680
             bool ignore_not_existing)
1643
1681
{
1644
1682
  int digit;
1645
1683
  VAR *v;
 
1684
 
1646
1685
  if (*var_name != '$')
1647
1686
    goto err;
1648
1687
  digit = *++var_name - '0';
1664
1703
      die("Too long variable name: %s", save_var_name);
1665
1704
 
1666
1705
    string save_var_name_str(save_var_name, length);
1667
 
    var_hash_t::iterator iter= var_hash.find(save_var_name_str);
 
1706
    drizzled::hash_map<string, VAR*>::iterator iter=
 
1707
      var_hash.find(save_var_name_str);
1668
1708
    if (iter == var_hash.end())
1669
1709
    {
1670
1710
      char buff[MAX_VAR_NAME_LENGTH+1];
1674
1714
    }
1675
1715
    else
1676
1716
    {
1677
 
      v= iter->second;
 
1717
      v= (*iter).second;
1678
1718
    }
1679
1719
    var_name--;  /* Point at last character */
1680
1720
  }
1681
1721
  else
1682
 
    v = &var_reg[digit];
 
1722
    v = var_reg + digit;
1683
1723
 
1684
1724
  if (!raw && v->int_dirty)
1685
1725
  {
1701
1741
static VAR *var_obtain(const char *name, int len)
1702
1742
{
1703
1743
  string var_name(name, len);
1704
 
  var_hash_t::iterator iter= var_hash.find(var_name);
 
1744
  drizzled::hash_map<string, VAR*>::iterator iter=
 
1745
    var_hash.find(var_name);
1705
1746
  if (iter != var_hash.end())
1706
 
    return iter->second;
1707
 
  return var_hash[var_name] = var_init(0, name, len, "", 0);
 
1747
    return (*iter).second;
 
1748
  VAR *v = var_init(0, name, len, "", 0);
 
1749
  var_hash.insert(make_pair(var_name, v));
 
1750
  return v;
1708
1751
}
1709
1752
 
1710
1753
 
1731
1774
    v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
1732
1775
  }
1733
1776
  else
1734
 
    v= &var_reg[digit];
 
1777
    v= var_reg + digit;
1735
1778
 
1736
1779
  eval_expr(v, var_val, (const char**) &var_val_end);
1737
1780
 
2015
2058
    eval_expr(var, value, 0);
2016
2059
  }
2017
2060
  drizzle_result_free(&res);
 
2061
 
 
2062
  return;
2018
2063
}
2019
2064
 
2020
2065
 
2045
2090
{
2046
2091
  if (*p == '$')
2047
2092
  {
2048
 
    VAR *vp= var_get(p, p_end, 0, 0);
2049
 
    if (vp)
 
2093
    VAR *vp;
 
2094
    if ((vp= var_get(p, p_end, 0, 0)))
2050
2095
      var_copy(v, vp);
2051
2096
    return;
2052
2097
  }
2102
2147
 
2103
2148
  if (!internal::test_if_hard_path(name))
2104
2149
  {
2105
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
 
2150
    sprintf(buff,"%s%s",opt_basedir,name);
2106
2151
    name=buff;
2107
2152
  }
2108
2153
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2109
2154
 
 
2155
  if (cur_file == file_stack_end)
 
2156
    die("Source directives are nesting too deep");
2110
2157
  cur_file++;
2111
 
  if (cur_file == &*file_stack.end())
2112
 
    die("Source directives are nesting too deep");
2113
2158
  if (!(cur_file->file= fopen(buff, "r")))
2114
2159
  {
2115
2160
    cur_file--;
2156
2201
    ; /* Do nothing */
2157
2202
  else
2158
2203
  {
2159
 
    if (! opt_testdir.empty())
 
2204
    if (opt_testdir != NULL)
2160
2205
    {
2161
2206
      string testdir(opt_testdir);
2162
2207
      if (testdir[testdir.length()] != '/')
2171
2216
}
2172
2217
 
2173
2218
 
2174
 
static void init_builtin_echo()
 
2219
static void init_builtin_echo(void)
2175
2220
{
2176
2221
  builtin_echo[0]= 0;
 
2222
  return;
2177
2223
}
2178
2224
 
2179
2225
 
2425
2471
 
2426
2472
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
2427
2473
  handle_command_error(command, error);
 
2474
  return;
2428
2475
}
2429
2476
 
2430
2477
 
2459
2506
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2460
2507
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2461
2508
  handle_command_error(command, error);
 
2509
  return;
2462
2510
}
2463
2511
 
2464
2512
 
2496
2544
    die("You must write a 4 digit octal number for mode");
2497
2545
 
2498
2546
  handle_command_error(command, chmod(ds_file.c_str(), mode));
 
2547
  return;
2499
2548
}
2500
2549
 
2501
2550
 
2525
2574
 
2526
2575
  error= (access(ds_filename.c_str(), F_OK) != 0);
2527
2576
  handle_command_error(command, error);
 
2577
  return;
2528
2578
}
2529
2579
 
2530
2580
 
2553
2603
 
2554
2604
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
2555
2605
  handle_command_error(command, error);
 
2606
  return;
2556
2607
}
2557
2608
 
2558
2609
/*
2580
2631
 
2581
2632
  error= rmdir(ds_dirname.c_str()) != 0;
2582
2633
  handle_command_error(command, error);
 
2634
  return;
2583
2635
}
2584
2636
 
2585
2637
 
2818
2870
  }
2819
2871
 
2820
2872
  handle_command_error(command, error);
 
2873
  return;
2821
2874
}
2822
2875
 
2823
2876
 
2867
2920
 
2868
2921
  if (drizzle_quit(&con->con,&result, &ret))
2869
2922
    drizzle_result_free(&result);
 
2923
 
 
2924
  return;
2870
2925
}
2871
2926
 
2872
2927
 
2963
3018
  internal::my_delete(temp_file_path, MYF(0));
2964
3019
 
2965
3020
  handle_command_error(command, WEXITSTATUS(error));
 
3021
  return;
2966
3022
}
2967
3023
 
2968
3024
 
3065
3121
  if (!master_pos.file[0])
3066
3122
    die("Calling 'sync_with_master' without calling 'save_master_pos'");
3067
3123
 
3068
 
  snprintf(query_buf, sizeof(query_buf), "select master_pos_wait('%s', %ld)", master_pos.file,
 
3124
  sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
3069
3125
          master_pos.pos + offset);
3070
3126
 
3071
3127
wait_for_position:
3136
3192
  when ndb binlog is on, this call will wait until last updated epoch
3137
3193
  (locally in the drizzled) has been received into the binlog
3138
3194
*/
3139
 
static int do_save_master_pos()
 
3195
static int do_save_master_pos(void)
3140
3196
{
3141
3197
  drizzle_result_st res;
3142
3198
  drizzle_return_t ret;
3252
3308
  bool error= false;
3253
3309
  char *p= command->first_argument;
3254
3310
  char *sleep_start, *sleep_end= command->end;
3255
 
  double sleep_val= 0;
 
3311
  double sleep_val;
3256
3312
 
3257
3313
  while (my_isspace(charset_info, *p))
3258
3314
    p++;
3275
3331
    sleep_val= opt_sleep;
3276
3332
 
3277
3333
  if (sleep_val)
3278
 
    usleep(sleep_val * 1000000);
 
3334
    usleep((uint32_t) (sleep_val * 1000000L));
3279
3335
  command->last_argument= sleep_end;
3280
3336
  return 0;
3281
3337
}
3282
3338
 
3283
3339
 
3284
 
static void do_get_file_name(st_command *command, string &dest)
 
3340
static void do_get_file_name(struct st_command *command, string &dest)
3285
3341
{
3286
 
  char *p= command->first_argument;
 
3342
  char *p= command->first_argument, *name;
3287
3343
  if (!*p)
3288
3344
    die("Missing file name argument");
3289
 
  char *name= p;
 
3345
  name= p;
3290
3346
  while (*p && !my_isspace(charset_info,*p))
3291
3347
    p++;
3292
3348
  if (*p)
3293
3349
    *p++= 0;
3294
3350
  command->last_argument= p;
3295
 
  if (! opt_testdir.empty())
 
3351
  if (opt_testdir != NULL)
3296
3352
  {
3297
3353
    dest= opt_testdir;
3298
3354
    if (dest[dest.length()] != '/')
3321
3377
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3322
3378
}
3323
3379
 
3324
 
static void fill_global_error_names()
3325
 
{
3326
 
  drizzle_result_st res;
3327
 
  drizzle_return_t ret;
3328
 
  drizzle_row_t row;
3329
 
  drizzle_con_st *con= &cur_con->con;
3330
 
 
3331
 
  global_error_names.clear();
3332
 
 
3333
 
  const std::string ds_query("select error_name, error_code "
3334
 
                             "from data_dictionary.errors");
3335
 
  if (drizzle_query_str(con, &res, ds_query.c_str(), &ret) == NULL ||
3336
 
      ret != DRIZZLE_RETURN_OK)
3337
 
  {
3338
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3339
 
    {
3340
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
3341
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
3342
 
      drizzle_result_free(&res);
3343
 
    }
3344
 
    else
3345
 
    {
3346
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3347
 
          drizzle_con_error(con));
3348
 
    }
3349
 
  }
3350
 
  if (drizzle_result_column_count(&res) == 0 ||
3351
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3352
 
  {
3353
 
    drizzle_result_free(&res);
3354
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
3355
 
  }
3356
 
 
3357
 
  while ((row= drizzle_row_next(&res)) && row[0])
3358
 
  {
3359
 
    /*
3360
 
      Concatenate all fields in the first row with tab in between
3361
 
      and assign that string to the $variable
3362
 
    */
3363
 
    size_t *lengths= drizzle_row_field_sizes(&res);
3364
 
    try
3365
 
    {
3366
 
      global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
3367
 
    }
3368
 
    catch (boost::bad_lexical_cast &ex)
3369
 
    {
3370
 
      drizzle_result_free(&res);
3371
 
      die("Invalid error_code from Drizzle: %s", ex.what());
3372
 
    }
3373
 
 
3374
 
  }
3375
 
 
3376
 
  drizzle_result_free(&res);
3377
 
}
3378
 
 
3379
3380
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3380
3381
{
3381
3382
  size_t err_name_len= error_end - error_name;
3382
3383
  string error_name_s(error_name, err_name_len);
3383
3384
 
3384
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3385
 
  if (it != global_error_names.end())
3386
 
    return it->second;
3387
 
 
3388
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3389
 
  return 0;
 
3385
  uint32_t code= global_error_names.getErrorCode(error_name_s);
 
3386
 
 
3387
  if (!code)
 
3388
    die("Unknown SQL error name '%s'", error_name_s.c_str());
 
3389
 
 
3390
  return(code);
3390
3391
}
3391
3392
 
3392
3393
static void do_get_errcodes(struct st_command *command)
3454
3455
    {
3455
3456
      die("The error name definition must start with an uppercase E");
3456
3457
    }
3457
 
    else if (*p == 'H')
 
3458
    else
3458
3459
    {
3459
 
      /* Error name string */
3460
 
 
3461
 
      to->code.errnum= get_errcode_from_name(p, end);
 
3460
      long val;
 
3461
      char *start= p;
 
3462
      /* Check that the string passed to str2int only contain digits */
 
3463
      while (*p && p != end)
 
3464
      {
 
3465
        if (!my_isdigit(charset_info, *p))
 
3466
          die("Invalid argument to error: '%s' - "              \
 
3467
              "the errno may only consist of digits[0-9]",
 
3468
              command->first_argument);
 
3469
        p++;
 
3470
      }
 
3471
 
 
3472
      /* Convert the sting to int */
 
3473
      istringstream buff(start);
 
3474
      if ((buff >> val).fail())
 
3475
        die("Invalid argument to error: '%s'", command->first_argument);
 
3476
 
 
3477
      to->code.errnum= (uint32_t) val;
3462
3478
      to->type= ERR_ERRNO;
3463
3479
    }
3464
 
    else
3465
 
    {
3466
 
      die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3467
 
    }
3468
3480
    to++;
3469
3481
    count++;
3470
3482
 
3673
3685
*/
3674
3686
 
3675
3687
static void safe_connect(drizzle_con_st *con, const char *name,
3676
 
                         const string host, const string user, const char *pass,
3677
 
                         const string db, uint32_t port)
 
3688
                         const char *host, const char *user, const char *pass,
 
3689
                         const char *db, int port)
3678
3690
{
3679
 
  uint32_t failed_attempts= 0;
 
3691
  int failed_attempts= 0;
3680
3692
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
3681
3693
  drizzle_return_t ret;
3682
3694
 
3683
 
  drizzle_con_set_tcp(con, host.c_str(), port);
3684
 
  drizzle_con_set_auth(con, user.c_str(), pass);
3685
 
  drizzle_con_set_db(con, db.c_str());
 
3695
  drizzle_con_set_tcp(con, host, port);
 
3696
  drizzle_con_set_auth(con, user, pass);
 
3697
  drizzle_con_set_db(con, db);
3686
3698
  while((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
3687
3699
  {
3688
3700
    /*
3824
3836
 
3825
3837
static void do_connect(struct st_command *command)
3826
3838
{
3827
 
  uint32_t con_port= opt_port;
 
3839
  int con_port= opt_port;
3828
3840
  const char *con_options;
3829
 
  bool con_ssl= 0;
 
3841
  bool con_ssl= 0, con_compress= 0;
3830
3842
  struct st_connection* con_slot;
3831
3843
 
3832
3844
  string ds_connection_name;
3892
3904
      end++;
3893
3905
    if (!strncmp(con_options, "SSL", 3))
3894
3906
      con_ssl= 1;
 
3907
    else if (!strncmp(con_options, "COMPRESS", 8))
 
3908
      con_compress= 1;
3895
3909
    else
3896
3910
      die("Illegal option to connect: %.*s",
3897
3911
          (int) (end - con_options), con_options);
3917
3931
    die("Failed on drizzle_create()");
3918
3932
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
3919
3933
    die("Failed on drizzle_con_create()");
3920
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
3934
  if (opt_mysql)
 
3935
    drizzle_con_add_options(&con_slot->con, DRIZZLE_CON_MYSQL);
3921
3936
 
3922
3937
  /* Use default db name */
3923
3938
  if (ds_database.length() == 0)
4004
4019
{
4005
4020
  char *p= command->first_argument;
4006
4021
  const char *expr_start, *expr_end;
 
4022
  VAR v;
4007
4023
  const char *cmd_name= (cmd == cmd_while ? "while" : "if");
4008
4024
  bool not_expr= false;
4009
4025
 
4046
4062
  if (*p && *p != '{')
4047
4063
    die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
4048
4064
 
4049
 
  VAR v;
4050
4065
  var_init(&v,0,0,0,0);
4051
4066
  eval_expr(&v, expr_start, &expr_end);
4052
4067
 
4182
4197
      }
4183
4198
      free((unsigned char*) cur_file->file_name);
4184
4199
      cur_file->file_name= 0;
4185
 
      if (cur_file == file_stack.data())
 
4200
      if (cur_file == file_stack)
4186
4201
      {
4187
4202
        /* We're back at the first file, check if
4188
4203
           all { have matching }
4416
4431
        end++;
4417
4432
      save= *end;
4418
4433
      *end= 0;
4419
 
      type= command_typelib.find_type(start, 1+2);
 
4434
      type= find_type(start, &command_typelib, 1+2);
4420
4435
      if (type)
4421
4436
        warning_msg("Embedded drizzletest command '--%s' detected in "
4422
4437
                    "query '%s' was this intentional? ",
4481
4496
  return;
4482
4497
}
4483
4498
 
 
4499
 
 
4500
 
4484
4501
/*
4485
4502
  Create a command from a set of lines
4486
4503
 
4498
4515
  terminated by new line '\n' regardless how many "delimiter" it contain.
4499
4516
*/
4500
4517
 
4501
 
#define MAX_QUERY (768*1024*2) /* 256K -- a test in sp-big is >128K */
 
4518
#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */
4502
4519
static char read_command_buf[MAX_QUERY];
4503
4520
 
4504
4521
static int read_command(struct st_command** command_ptr)
4560
4577
  return(0);
4561
4578
}
4562
4579
 
 
4580
 
 
4581
static struct my_option my_long_options[] =
 
4582
{
 
4583
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
4584
   0, 0, 0, 0, 0, 0},
 
4585
  {"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
 
4586
   (char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4587
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
4588
   "Directory where character sets are.", (char**) &opt_charsets_dir,
 
4589
   (char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4590
  {"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
 
4591
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4592
  {"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
 
4593
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4594
  {"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
 
4595
   (char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4596
  {"testdir", OPT_TESTDIR, "Path to use to search for test files",
 
4597
   (char**) &opt_testdir,
 
4598
   (char**) &opt_testdir, 0,GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4599
  {"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
 
4600
   (char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4601
  {"mark-progress", OPT_MARK_PROGRESS,
 
4602
   "Write linenumber and elapsed time to <testname>.progress ",
 
4603
   (char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
 
4604
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4605
  {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
 
4606
   "Max number of connection attempts when connecting to server",
 
4607
   (char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
 
4608
   GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
 
4609
  {"mysql", 'm', N_("Use MySQL Protocol."),
 
4610
   (char**) &opt_mysql, (char**) &opt_mysql, 0, GET_BOOL, NO_ARG, 1, 0, 0,
 
4611
   0, 0, 0},
 
4612
  {"password", 'P', "Password to use when connecting to server.",
 
4613
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
4614
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
 
4615
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
4616
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
4617
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4618
  {"quiet", 's', "Suppress all normal output.", (char**) &silent,
 
4619
   (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4620
  {"record", 'r', "Record output of test_file into result file.",
 
4621
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4622
  {"result-file", 'R', "Read/Store result from/in this file.",
 
4623
   (char**) &result_file_name, (char**) &result_file_name, 0,
 
4624
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4625
  {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
 
4626
   (char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4627
  {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
 
4628
   (char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
 
4629
   0, 0, 0},
 
4630
  {"tail-lines", OPT_TAIL_LINES,
 
4631
   "Number of lines of the resul to include in a failure report",
 
4632
   (char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
 
4633
   GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
 
4634
  {"test-file", 'x', "Read test from/in this file (default stdin).",
 
4635
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4636
  {"timer-file", 'm', "File where the timing in micro seconds is stored.",
 
4637
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4638
  {"tmpdir", 't', "Temporary directory where sockets are put.",
 
4639
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4640
  {"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
 
4641
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4642
  {"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
 
4643
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4644
  {"version", 'V', "Output version information and exit.",
 
4645
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4646
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
4647
};
 
4648
 
 
4649
 
 
4650
static void print_version(void)
 
4651
{
 
4652
  printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
 
4653
         drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
 
4654
}
 
4655
 
 
4656
static void usage(void)
 
4657
{
 
4658
  print_version();
 
4659
  printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
 
4660
  printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
 
4661
  printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
 
4662
  printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
 
4663
  printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
 
4664
  my_print_help(my_long_options);
 
4665
  printf("  --no-defaults       Don't read default options from any options file.\n");
 
4666
  my_print_variables(my_long_options);
 
4667
}
 
4668
 
 
4669
int get_one_option(int optid, const struct my_option *, char *argument)
 
4670
{
 
4671
  char *endchar= NULL;
 
4672
  uint64_t temp_drizzle_port= 0;
 
4673
 
 
4674
  switch(optid) {
 
4675
  case 'r':
 
4676
    record = 1;
 
4677
    break;
 
4678
  case 'x':
 
4679
  {
 
4680
    char buff[FN_REFLEN];
 
4681
    if (!internal::test_if_hard_path(argument))
 
4682
    {
 
4683
      sprintf(buff,"%s%s",opt_basedir,argument);
 
4684
      argument= buff;
 
4685
    }
 
4686
    internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4687
    assert(cur_file == file_stack && cur_file->file == 0);
 
4688
    if (!(cur_file->file= fopen(buff, "r")))
 
4689
    {
 
4690
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
 
4691
      return EXIT_ARGUMENT_INVALID;
 
4692
    }
 
4693
    if (!(cur_file->file_name= strdup(buff)))
 
4694
    {
 
4695
      fprintf(stderr, _("Out of memory"));
 
4696
      return EXIT_OUT_OF_MEMORY;
 
4697
    }
 
4698
    cur_file->lineno= 1;
 
4699
    break;
 
4700
  }
 
4701
  case 'm':
 
4702
  {
 
4703
    static char buff[FN_REFLEN];
 
4704
    if (!internal::test_if_hard_path(argument))
 
4705
    {
 
4706
      sprintf(buff,"%s%s",opt_basedir,argument);
 
4707
      argument= buff;
 
4708
    }
 
4709
    internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4710
    timer_file= buff;
 
4711
    unlink(timer_file);       /* Ignore error, may not exist */
 
4712
    break;
 
4713
  }
 
4714
  case 'p':
 
4715
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
4716
    /* if there is an alpha character this is not a valid port */
 
4717
    if (strlen(endchar) != 0)
 
4718
    {
 
4719
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
4720
      return EXIT_ARGUMENT_INVALID;
 
4721
    }
 
4722
    /* If the port number is > 65535 it is not a valid port
 
4723
       This also helps with potential data loss casting unsigned long to a
 
4724
       uint32_t. */
 
4725
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
4726
    {
 
4727
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
4728
      return EXIT_ARGUMENT_INVALID;
 
4729
    }
 
4730
    else
 
4731
    {
 
4732
      opt_port= (uint32_t) temp_drizzle_port;
 
4733
    }
 
4734
    break;
 
4735
  case 'P':
 
4736
    if (argument)
 
4737
    {
 
4738
      if (opt_pass)
 
4739
        free(opt_pass);
 
4740
      opt_pass = strdup(argument);
 
4741
      if (opt_pass == NULL)
 
4742
      {
 
4743
        fprintf(stderr, _("Out of memory"));
 
4744
        return EXIT_OUT_OF_MEMORY;
 
4745
      }
 
4746
      while (*argument)
 
4747
      {
 
4748
        /* Overwriting password with 'x' */
 
4749
        *argument++= 'x';
 
4750
      }
 
4751
      tty_password= 0;
 
4752
    }
 
4753
    else
 
4754
      tty_password= 1;
 
4755
    break;
 
4756
  case 't':
 
4757
    strncpy(TMPDIR, argument, sizeof(TMPDIR));
 
4758
    break;
 
4759
  case 'V':
 
4760
    print_version();
 
4761
    exit(0);
 
4762
  case '?':
 
4763
    usage();
 
4764
    exit(0);
 
4765
  }
 
4766
  return 0;
 
4767
}
 
4768
 
 
4769
 
 
4770
static int parse_args(int argc, char **argv)
 
4771
{
 
4772
  internal::load_defaults("drizzle",load_default_groups,&argc,&argv);
 
4773
  default_argv= argv;
 
4774
 
 
4775
  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
 
4776
    exit(1);
 
4777
 
 
4778
  if (argc > 1)
 
4779
  {
 
4780
    usage();
 
4781
    exit(1);
 
4782
  }
 
4783
  if (argc == 1)
 
4784
    opt_db= *argv;
 
4785
  if (tty_password)
 
4786
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
 
4787
 
 
4788
  return 0;
 
4789
}
 
4790
 
4563
4791
/*
4564
4792
  Write the content of str into file
4565
4793
 
4578
4806
  int flags= O_WRONLY | O_CREAT;
4579
4807
  if (!internal::test_if_hard_path(fname))
4580
4808
  {
4581
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
 
4809
    sprintf(buff,"%s%s",opt_basedir,fname);
4582
4810
    fname= buff;
4583
4811
  }
4584
4812
  internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4614
4842
void dump_result_to_log_file(const char *buf, int size)
4615
4843
{
4616
4844
  char log_file[FN_REFLEN];
4617
 
  str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(), ".log",
4618
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4845
  str_to_file(internal::fn_format(log_file, result_file_name, opt_logdir, ".log",
 
4846
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4619
4847
                        MY_REPLACE_EXT),
4620
4848
              buf, size);
4621
4849
  fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
4622
4850
          log_file);
4623
4851
}
4624
4852
 
4625
 
void dump_progress()
 
4853
void dump_progress(void)
4626
4854
{
4627
4855
  char progress_file[FN_REFLEN];
4628
 
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4629
 
                        opt_logdir.c_str(), ".progress",
4630
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4856
  str_to_file(internal::fn_format(progress_file, result_file_name,
 
4857
                        opt_logdir, ".progress",
 
4858
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4631
4859
                        MY_REPLACE_EXT),
4632
4860
              ds_progress.c_str(), ds_progress.length());
4633
4861
}
4634
4862
 
4635
 
void dump_warning_messages()
 
4863
void dump_warning_messages(void)
4636
4864
{
4637
4865
  char warn_file[FN_REFLEN];
4638
4866
 
4639
 
  str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(), ".warnings",
4640
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
4867
  str_to_file(internal::fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
 
4868
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4641
4869
                        MY_REPLACE_EXT),
4642
4870
              ds_warning_messages.c_str(), ds_warning_messages.length());
4643
4871
}
4697
4925
    for (i = 0; i < num_fields; i++)
4698
4926
    {
4699
4927
      column= drizzle_column_next(res);
4700
 
      if (row[i] && (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY))
4701
 
      {
4702
 
        if (boost::lexical_cast<uint32_t>(row[i]))
4703
 
        {
4704
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4705
 
          {
4706
 
            append_field(ds, i, column, "YES", 3, false);
4707
 
          }
4708
 
          else
4709
 
          {
4710
 
            append_field(ds, i, column, "TRUE", 4, false);
4711
 
          }
4712
 
        }
4713
 
        else
4714
 
        {
4715
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4716
 
          {
4717
 
            append_field(ds, i, column, "NO", 2, false);
4718
 
          }
4719
 
          else
4720
 
          {
4721
 
            append_field(ds, i, column, "FALSE", 5, false);
4722
 
          }
4723
 
        }
4724
 
      }
4725
 
      else
4726
 
      {
4727
 
        append_field(ds, i, column,
4728
 
                     (const char*)row[i], lengths[i], !row[i]);
4729
 
      }
 
4928
      append_field(ds, i, column,
 
4929
                   (const char*)row[i], lengths[i], !row[i]);
4730
4930
    }
4731
4931
    if (!display_result_vertically)
4732
4932
      ds->append("\n");
4770
4970
    ds->append("\t", 1);
4771
4971
    replace_append_uint(ds, drizzle_column_size(column));
4772
4972
    ds->append("\t", 1);
4773
 
    if (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4774
 
    {
4775
 
      replace_append_uint(ds, 1);
4776
 
    }
4777
 
    else
4778
 
    {
4779
 
      replace_append_uint(ds, drizzle_column_max_size(column));
4780
 
    }
 
4973
    replace_append_uint(ds, drizzle_column_max_size(column));
4781
4974
    ds->append("\t", 1);
4782
4975
    ds->append((char*) ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL) ? "N" : "Y"), 1);
4783
4976
    ds->append("\t", 1);
5274
5467
 
5275
5468
  save= command->query[command->first_word_len];
5276
5469
  command->query[command->first_word_len]= 0;
5277
 
  type= command_typelib.find_type(command->query, 1+2);
 
5470
  type= find_type(command->query, &command_typelib, 1+2);
5278
5471
  command->query[command->first_word_len]= save;
5279
5472
  if (type > 0)
5280
5473
  {
5318
5511
        */
5319
5512
        save= command->query[command->first_word_len-1];
5320
5513
        command->query[command->first_word_len-1]= 0;
5321
 
        if (command_typelib.find_type(command->query, 1+2) > 0)
 
5514
        if (find_type(command->query, &command_typelib, 1+2) > 0)
5322
5515
          die("Extra delimiter \";\" found");
5323
5516
        command->query[command->first_word_len-1]= save;
5324
5517
 
5370
5563
 
5371
5564
}
5372
5565
 
5373
 
static void check_retries(uint32_t in_opt_max_connect_retries)
5374
 
{
5375
 
  if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5376
 
  {
5377
 
    cout << N_("Error: Invalid Value for opt_max_connect_retries"); 
5378
 
    exit(-1);
5379
 
  }
5380
 
  opt_max_connect_retries= in_opt_max_connect_retries;
5381
 
}
5382
 
 
5383
 
static void check_tail_lines(uint32_t in_opt_tail_lines)
5384
 
{
5385
 
  if (in_opt_tail_lines > 10000)
5386
 
  {
5387
 
    cout << N_("Error: Invalid Value for opt_tail_lines"); 
5388
 
    exit(-1);
5389
 
  }
5390
 
  opt_tail_lines= in_opt_tail_lines;
5391
 
}
5392
 
 
5393
 
static void check_sleep(int32_t in_opt_sleep)
5394
 
{
5395
 
  if (in_opt_sleep < -1)
5396
 
  {
5397
 
    cout << N_("Error: Invalid Value for opt_sleep"); 
5398
 
    exit(-1);
5399
 
  }
5400
 
  opt_sleep= in_opt_sleep;
5401
 
}
5402
5566
 
5403
5567
int main(int argc, char **argv)
5404
5568
{
5405
 
try
5406
 
{
5407
5569
  struct st_command *command;
5408
5570
  bool q_send_flag= 0, abort_flag= 0;
5409
5571
  uint32_t command_executed= 0, last_command_executed= 0;
5410
5572
  string save_file("");
5411
5573
  struct stat res_info;
 
5574
  MY_INIT(argv[0]);
5412
5575
 
5413
5576
  TMPDIR[0]= 0;
5414
5577
 
5415
 
  internal::my_init();
5416
 
 
5417
 
  po::options_description commandline_options("Options used only in command line");
5418
 
  commandline_options.add_options()
5419
 
  ("help,?", "Display this help and exit.")
5420
 
  ("mark-progress", po::value<bool>(&opt_mark_progress)->default_value(false)->zero_tokens(),
5421
 
  "Write linenumber and elapsed time to <testname>.progress ")
5422
 
  ("sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
5423
 
  "Sleep always this many seconds on sleep commands.")
5424
 
  ("test-file,x", po::value<string>(),
5425
 
  "Read test from/in this file (default stdin).")
5426
 
  ("timer-file,f", po::value<string>(),
5427
 
  "File where the timing in micro seconds is stored.")
5428
 
  ("tmpdir,t", po::value<string>(),
5429
 
  "Temporary directory where sockets are put.")
5430
 
  ("verbose,v", po::value<bool>(&verbose)->default_value(false),
5431
 
  "Write more.")
5432
 
  ("version,V", "Output version information and exit.")
5433
 
  ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
5434
 
  "Configuration file defaults are not used if no-defaults is set")
5435
 
  ;
5436
 
 
5437
 
  po::options_description test_options("Options specific to the drizzleimport");
5438
 
  test_options.add_options()
5439
 
  ("basedir,b", po::value<string>(&opt_basedir)->default_value(""),
5440
 
  "Basedir for tests.")
5441
 
  ("character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(""),
5442
 
  "Directory where character sets are.")
5443
 
  ("database,D", po::value<string>(&opt_db)->default_value(""),
5444
 
  "Database to use.")
5445
 
  ("include,i", po::value<string>(&opt_include)->default_value(""),
5446
 
  "Include SQL before each test case.")  
5447
 
  ("testdir", po::value<string>(&opt_testdir)->default_value(""),
5448
 
  "Path to use to search for test files")
5449
 
  ("logdir", po::value<string>(&opt_logdir)->default_value(""),
5450
 
  "Directory for log files")
5451
 
  ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
5452
 
  "Max number of connection attempts when connecting to server")
5453
 
  ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5454
 
  "Suppress all normal output.")
5455
 
  ("record,r", "Record output of test_file into result file.")
5456
 
  ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
5457
 
  "Read/Store result from/in this file.")
5458
 
  ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5459
 
  "Suppress all normal output. Synonym for --quiet.")
5460
 
  ("tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
5461
 
  "Number of lines of the resul to include in a failure report")
5462
 
  ;
5463
 
 
5464
 
  po::options_description client_options("Options specific to the client");
5465
 
  client_options.add_options()
5466
 
 
5467
 
  ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
5468
 
  "Connect to host.")
5469
 
  ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
5470
 
  "Password to use when connecting to server.")
5471
 
  ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
5472
 
  "Port number to use for connection or 0 for default")
5473
 
  ("protocol", po::value<string>(&opt_protocol),
5474
 
  "The protocol of connection (mysql or drizzle).")
5475
 
  ("user,u", po::value<string>(&opt_user)->default_value(""),
5476
 
  "User for login.")
5477
 
  ;
5478
 
 
5479
 
  po::positional_options_description p;
5480
 
  p.add("database", 1);
5481
 
 
5482
 
  po::options_description long_options("Allowed Options");
5483
 
  long_options.add(commandline_options).add(test_options).add(client_options);
5484
 
 
5485
 
  std::string system_config_dir_test(SYSCONFDIR); 
5486
 
  system_config_dir_test.append("/drizzle/drizzletest.cnf");
5487
 
 
5488
 
  std::string system_config_dir_client(SYSCONFDIR); 
5489
 
  system_config_dir_client.append("/drizzle/client.cnf");
5490
 
 
5491
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5492
 
 
5493
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
5494
 
  {
5495
 
    const char *homedir= getenv("HOME");
5496
 
    if (homedir != NULL)
5497
 
      user_config_dir.replace(0, 1, homedir);
5498
 
  }
5499
 
 
5500
 
  po::variables_map vm;
5501
 
 
5502
 
  // Disable allow_guessing
5503
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5504
 
 
5505
 
  po::store(po::command_line_parser(argc, argv).options(long_options).
5506
 
            style(style).positional(p).extra_parser(parse_password_arg).run(),
5507
 
            vm);
5508
 
 
5509
 
  if (! vm["no-defaults"].as<bool>())
5510
 
  {
5511
 
    std::string user_config_dir_test(user_config_dir);
5512
 
    user_config_dir_test.append("/drizzle/drizzletest.cnf"); 
5513
 
 
5514
 
    std::string user_config_dir_client(user_config_dir);
5515
 
    user_config_dir_client.append("/drizzle/client.cnf");
5516
 
 
5517
 
    ifstream user_test_ifs(user_config_dir_test.c_str());
5518
 
    po::store(parse_config_file(user_test_ifs, test_options), vm);
5519
 
 
5520
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
5521
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
5522
 
 
5523
 
    ifstream system_test_ifs(system_config_dir_test.c_str());
5524
 
    store(parse_config_file(system_test_ifs, test_options), vm);
5525
 
 
5526
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
5527
 
    po::store(parse_config_file(system_client_ifs, client_options), vm);
5528
 
  }
5529
 
 
5530
 
  po::notify(vm);
5531
 
 
5532
5578
  /* Init expected errors */
5533
5579
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5534
5580
 
5539
5585
  next_con= connections + 1;
5540
5586
 
5541
5587
  /* Init file stack */
5542
 
  memset(file_stack.data(), 0, sizeof(file_stack));
5543
 
  cur_file= file_stack.data();
 
5588
  memset(file_stack, 0, sizeof(file_stack));
 
5589
  file_stack_end=
 
5590
    file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
 
5591
  cur_file= file_stack;
5544
5592
 
5545
5593
  /* Init block stack */
5546
5594
  memset(block_stack, 0, sizeof(block_stack));
5563
5611
  ds_progress.reserve(2048);
5564
5612
  ds_warning_messages.reserve(2048);
5565
5613
 
5566
 
 
5567
 
  if (vm.count("record"))
5568
 
  {
5569
 
    record = 1;
5570
 
  }
5571
 
 
5572
 
  if (vm.count("test-file"))
5573
 
  {
5574
 
    string tmp= vm["test-file"].as<string>();
5575
 
    char buff[FN_REFLEN];
5576
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5577
 
    {
5578
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5579
 
      tmp= buff;
5580
 
    }
5581
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5582
 
    assert(cur_file == file_stack.data() && cur_file->file == 0);
5583
 
    if (!(cur_file->file= fopen(buff, "r")))
5584
 
    {
5585
 
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5586
 
      return EXIT_ARGUMENT_INVALID;
5587
 
    }
5588
 
    if (!(cur_file->file_name= strdup(buff)))
5589
 
    {
5590
 
      fprintf(stderr, _("Out of memory"));
5591
 
      return EXIT_OUT_OF_MEMORY;
5592
 
    }
5593
 
    cur_file->lineno= 1;
5594
 
  }
5595
 
 
5596
 
  if (vm.count("timer-file"))
5597
 
  {
5598
 
    string tmp= vm["timer-file"].as<string>().c_str();
5599
 
    static char buff[FN_REFLEN];
5600
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5601
 
    {
5602
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5603
 
      tmp= buff;
5604
 
    }
5605
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5606
 
    timer_file= buff;
5607
 
    unlink(timer_file);       /* Ignore error, may not exist */
5608
 
  }
5609
 
 
5610
 
  if (vm.count("protocol"))
5611
 
  {
5612
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
5613
 
      opt_protocol.begin(), ::tolower);
5614
 
 
5615
 
    if (not opt_protocol.compare("mysql"))
5616
 
      use_drizzle_protocol=false;
5617
 
    else if (not opt_protocol.compare("drizzle"))
5618
 
      use_drizzle_protocol=true;
5619
 
    else
5620
 
    {
5621
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5622
 
      exit(-1);
5623
 
    }
5624
 
  }
5625
 
 
5626
 
  if (vm.count("port"))
5627
 
  {
5628
 
    /* If the port number is > 65535 it is not a valid port
5629
 
       This also helps with potential data loss casting unsigned long to a
5630
 
       uint32_t. */
5631
 
    if (opt_port > 65535)
5632
 
    {
5633
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
5634
 
      exit(EXIT_ARGUMENT_INVALID);
5635
 
    }
5636
 
  }
5637
 
 
5638
 
  if( vm.count("password") )
5639
 
  {
5640
 
    if (!opt_password.empty())
5641
 
      opt_password.erase();
5642
 
    if (password == PASSWORD_SENTINEL)
5643
 
    {
5644
 
      opt_password= "";
5645
 
    }
5646
 
    else
5647
 
    {
5648
 
      opt_password= password;
5649
 
      tty_password= false;
5650
 
    }
5651
 
  }
5652
 
  else
5653
 
  {
5654
 
      tty_password= true;
5655
 
  }
5656
 
 
5657
 
  if (vm.count("tmpdir"))
5658
 
  {
5659
 
    strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
5660
 
  }
5661
 
 
5662
 
  if (vm.count("version"))
5663
 
  {
5664
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5665
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5666
 
    exit(0);
5667
 
  }
5668
 
  
5669
 
  if (vm.count("help"))
5670
 
  {
5671
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5672
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5673
 
    printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
5674
 
    printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5675
 
    printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
5676
 
    printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5677
 
    printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5678
 
    exit(0);
5679
 
  }
5680
 
 
5681
 
  if (tty_password)
5682
 
  {
5683
 
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
5684
 
  }
 
5614
  parse_args(argc, argv);
5685
5615
 
5686
5616
  server_initialized= 1;
5687
 
  if (cur_file == file_stack.data() && cur_file->file == 0)
 
5617
  if (cur_file == file_stack && cur_file->file == 0)
5688
5618
  {
5689
5619
    cur_file->file= stdin;
5690
5620
    cur_file->file_name= strdup("<stdin>");
5697
5627
    die("Failed in drizzle_create()");
5698
5628
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5699
5629
    die("Failed in drizzle_con_create()");
5700
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
5630
  if (opt_mysql)
 
5631
    drizzle_con_add_options(&cur_con->con, DRIZZLE_CON_MYSQL);
5701
5632
 
5702
5633
  if (!(cur_con->name = strdup("default")))
5703
5634
    die("Out of memory");
 
5635
 
5704
5636
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5705
5637
               opt_db, opt_port);
5706
5638
 
5707
 
  fill_global_error_names();
5708
 
 
5709
5639
  /* Use all time until exit if no explicit 'start_timer' */
5710
5640
  timer_start= timer_now();
5711
5641
 
5719
5649
  /* Update $drizzleclient_get_server_version to that of current connection */
5720
5650
  var_set_drizzleclient_get_server_version(&cur_con->con);
5721
5651
 
5722
 
  if (! opt_include.empty())
 
5652
  if (opt_include)
5723
5653
  {
5724
 
    open_file(opt_include.c_str());
 
5654
    open_file(opt_include);
5725
5655
  }
5726
5656
 
5727
5657
  while (!read_command(&command) && !abort_flag)
6025
5955
  */
6026
5956
  if (ds_res.length())
6027
5957
  {
6028
 
    if (! result_file_name.empty())
 
5958
    if (result_file_name)
6029
5959
    {
6030
5960
      /* A result file has been specified */
6031
5961
 
6032
5962
      if (record)
6033
5963
      {
6034
5964
        /* Recording - dump the output from test to result file */
6035
 
        str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
 
5965
        str_to_file(result_file_name, ds_res.c_str(), ds_res.length());
6036
5966
      }
6037
5967
      else
6038
5968
      {
6055
5985
  }
6056
5986
 
6057
5987
  if (!command_executed &&
6058
 
      ! result_file_name.empty() && !stat(result_file_name.c_str(), &res_info))
 
5988
      result_file_name && !stat(result_file_name, &res_info))
6059
5989
  {
6060
5990
    /*
6061
5991
      my_stat() successful on result file. Check if we have not run a
6067
5997
    die("No queries executed but result file found!");
6068
5998
  }
6069
5999
 
6070
 
  if ( opt_mark_progress && ! result_file_name.empty() )
 
6000
  if ( opt_mark_progress && result_file_name )
6071
6001
    dump_progress();
6072
6002
 
6073
6003
  /* Dump warning messages */
6074
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
6004
  if (result_file_name && ds_warning_messages.length())
6075
6005
    dump_warning_messages();
6076
6006
 
6077
6007
  timer_output();
6078
6008
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
6079
6009
  cleanup_and_exit(0);
6080
 
}
6081
 
 
6082
 
  catch(exception &err)
6083
 
  {
6084
 
    cerr<<err.what()<<endl;
6085
 
  }
6086
 
 
6087
6010
  return 0; /* Keep compiler happy too */
6088
6011
}
6089
6012
 
6109
6032
  the time between executing the two commands.
6110
6033
*/
6111
6034
 
6112
 
void timer_output()
 
6035
void timer_output(void)
6113
6036
{
6114
6037
  if (timer_file)
6115
6038
  {
6123
6046
}
6124
6047
 
6125
6048
 
6126
 
uint64_t timer_now()
 
6049
uint64_t timer_now(void)
6127
6050
{
6128
6051
#if defined(HAVE_GETHRTIME)
6129
6052
  return gethrtime()/1000/1000;
6163
6086
  start= buff= (char *)malloc(strlen(from)+1);
6164
6087
  while (*from)
6165
6088
  {
 
6089
    char *to;
6166
6090
    uint32_t column_number;
6167
6091
 
6168
 
    char *to= get_string(&buff, &from, command);
 
6092
    to= get_string(&buff, &from, command);
6169
6093
    if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
6170
6094
      die("Wrong column number to replace_column in '%s'", command->query);
6171
6095
    if (!*from)
6184
6108
 
6185
6109
void free_replace_column()
6186
6110
{
6187
 
  for (uint32_t i= 0 ; i < max_replace_column; i++)
 
6111
  uint32_t i;
 
6112
  for (i=0 ; i < max_replace_column ; i++)
6188
6113
  {
6189
 
    free(replace_column[i]);
6190
 
    replace_column[i]= 0;
 
6114
    if (replace_column[i])
 
6115
    {
 
6116
      free(replace_column[i]);
 
6117
      replace_column[i]= 0;
 
6118
    }
6191
6119
  }
6192
6120
  max_replace_column= 0;
6193
6121
}
6208
6136
} POINTER_ARRAY;
6209
6137
 
6210
6138
struct st_replace;
6211
 
struct st_replace *init_replace(const char **from, const char **to, uint32_t count,
6212
 
                                char *word_end_chars);
 
6139
struct st_replace *init_replace(char * *from, char * *to, uint32_t count,
 
6140
                                char * word_end_chars);
6213
6141
int insert_pointer_name(POINTER_ARRAY *pa,char * name);
6214
6142
void replace_strings_append(struct st_replace *rep, string* ds,
6215
6143
                            const char *from, int len);
 
6144
void free_pointer_array(POINTER_ARRAY *pa);
6216
6145
 
6217
 
st_replace *glob_replace= NULL;
6218
 
// boost::scoped_ptr<st_replace> glob_replace;
 
6146
struct st_replace *glob_replace= NULL;
6219
6147
 
6220
6148
/*
6221
6149
  Get arguments for replace. The syntax is:
6225
6153
  variable is replaced.
6226
6154
*/
6227
6155
 
6228
 
static void free_pointer_array(POINTER_ARRAY *pa)
6229
 
{
6230
 
  if (!pa->typelib.count)
6231
 
    return;
6232
 
  pa->typelib.count=0;
6233
 
  free((char*) pa->typelib.type_names);
6234
 
  pa->typelib.type_names=0;
6235
 
  free(pa->str);
6236
 
}
6237
 
 
6238
6156
void do_get_replace(struct st_command *command)
6239
6157
{
6240
6158
  uint32_t i;
6266
6184
    if (my_isspace(charset_info,i))
6267
6185
      *pos++= i;
6268
6186
  *pos=0;          /* End pointer */
6269
 
  if (!(glob_replace= init_replace(from_array.typelib.type_names,
6270
 
                                   to_array.typelib.type_names,
6271
 
                                   from_array.typelib.count,
 
6187
  if (!(glob_replace= init_replace((char**) from_array.typelib.type_names,
 
6188
                                   (char**) to_array.typelib.type_names,
 
6189
                                   (uint32_t) from_array.typelib.count,
6272
6190
                                   word_end_chars)))
6273
6191
    die("Can't initialize replace from '%s'", command->query);
6274
6192
  free_pointer_array(&from_array);
6281
6199
 
6282
6200
void free_replace()
6283
6201
{
6284
 
  free(glob_replace);
6285
 
  glob_replace=0;
 
6202
 
 
6203
  if (glob_replace)
 
6204
  {
 
6205
    free(glob_replace);
 
6206
    glob_replace=0;
 
6207
  }
 
6208
  return;
6286
6209
}
6287
6210
 
6288
6211
 
6302
6225
void replace_strings_append(REPLACE *rep, string* ds,
6303
6226
                            const char *str, int len)
6304
6227
{
6305
 
  REPLACE *rep_pos;
6306
 
  REPLACE_STRING *rep_str;
 
6228
  register REPLACE *rep_pos;
 
6229
  register REPLACE_STRING *rep_str;
6307
6230
  const char *start, *from;
6308
6231
 
6309
6232
 
6356
6279
                 i.e. repeat the matching until the end of the string */
6357
6280
};
6358
6281
 
6359
 
class st_replace_regex
 
6282
struct st_replace_regex
6360
6283
{
6361
 
public:
6362
 
  st_replace_regex(char* expr);
6363
 
  int multi_reg_replace(char* val);
 
6284
  DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
6364
6285
 
6365
6286
  /*
6366
6287
    Temporary storage areas for substitutions. To reduce unnessary copying
6369
6290
    st_regex substition. At the end of substitutions  buf points to the
6370
6291
    one containing the final result.
6371
6292
  */
6372
 
  typedef vector<st_regex> regex_arr_t;
6373
 
 
6374
 
  char* buf_;
 
6293
  char* buf;
6375
6294
  char* even_buf;
6376
6295
  char* odd_buf;
6377
6296
  int even_buf_len;
6378
6297
  int odd_buf_len;
6379
 
  boost::array<char, 8 << 10> buf0_;
6380
 
  boost::array<char, 8 << 10> buf1_;
6381
 
  regex_arr_t regex_arr;
6382
6298
};
6383
6299
 
6384
 
boost::scoped_ptr<st_replace_regex> glob_replace_regex;
 
6300
struct st_replace_regex *glob_replace_regex= 0;
6385
6301
 
6386
6302
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6387
6303
                char *string, int icase, int global);
6423
6339
  Returns: st_replace_regex struct with pairs of substitutions
6424
6340
*/
6425
6341
 
6426
 
st_replace_regex::st_replace_regex(char* expr)
 
6342
static struct st_replace_regex* init_replace_regex(char* expr)
6427
6343
{
 
6344
  struct st_replace_regex* res;
 
6345
  char* buf,*expr_end;
 
6346
  char* p;
 
6347
  char* buf_p;
6428
6348
  uint32_t expr_len= strlen(expr);
6429
6349
  char last_c = 0;
6430
 
  st_regex reg;
6431
 
 
6432
 
  char* buf= new char[expr_len];
6433
 
  char* expr_end= expr + expr_len;
6434
 
  char* p= expr;
6435
 
  char* buf_p= buf;
 
6350
  struct st_regex reg;
 
6351
 
 
6352
  res=(st_replace_regex*)malloc(sizeof(*res)+expr_len);
 
6353
  if (!res)
 
6354
    return NULL;
 
6355
  my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
 
6356
 
 
6357
  buf= (char*)res + sizeof(*res);
 
6358
  expr_end= expr + expr_len;
 
6359
  p= expr;
 
6360
  buf_p= buf;
6436
6361
 
6437
6362
  /* for each regexp substitution statement */
6438
6363
  while (p < expr_end)
6448
6373
 
6449
6374
    if (p == expr_end || ++p == expr_end)
6450
6375
    {
6451
 
      if (!regex_arr.empty())
 
6376
      if (res->regex_arr.elements)
6452
6377
        break;
6453
6378
      else
6454
6379
        goto err;
6487
6412
      p++;
6488
6413
      reg.global= 1;
6489
6414
    }
6490
 
    regex_arr.push_back(reg);
 
6415
 
 
6416
    /* done parsing the statement, now place it in regex_arr */
 
6417
    if (insert_dynamic(&res->regex_arr,(unsigned char*) &reg))
 
6418
      die("Out of memory");
6491
6419
  }
6492
 
  odd_buf_len= even_buf_len= buf0_.size();
6493
 
  even_buf= buf0_.data();
6494
 
  odd_buf= buf1_.data();
6495
 
  buf_= even_buf;
 
6420
  res->odd_buf_len= res->even_buf_len= 8192;
 
6421
  res->even_buf= (char*)malloc(res->even_buf_len);
 
6422
  res->odd_buf= (char*)malloc(res->odd_buf_len);
 
6423
  res->buf= res->even_buf;
6496
6424
 
6497
 
  return;
 
6425
  return res;
6498
6426
 
6499
6427
err:
 
6428
  free(res);
6500
6429
  die("Error parsing replace_regex \"%s\"", expr);
 
6430
  return 0;
6501
6431
}
6502
6432
 
6503
6433
/*
6519
6449
  in one pass
6520
6450
*/
6521
6451
 
6522
 
int st_replace_regex::multi_reg_replace(char* val)
 
6452
static int multi_reg_replace(struct st_replace_regex* r,char* val)
6523
6453
{
6524
 
  char* in_buf= val;
6525
 
  char* out_buf= even_buf;
6526
 
  int* buf_len_p= &even_buf_len;
6527
 
  buf_= 0;
 
6454
  uint32_t i;
 
6455
  char* in_buf, *out_buf;
 
6456
  int* buf_len_p;
 
6457
 
 
6458
  in_buf= val;
 
6459
  out_buf= r->even_buf;
 
6460
  buf_len_p= &r->even_buf_len;
 
6461
  r->buf= 0;
6528
6462
 
6529
6463
  /* For each substitution, do the replace */
6530
 
  BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
 
6464
  for (i= 0; i < r->regex_arr.elements; i++)
6531
6465
  {
 
6466
    struct st_regex re;
6532
6467
    char* save_out_buf= out_buf;
6533
 
    if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
6534
 
                     in_buf, i.icase, i.global))
 
6468
 
 
6469
    get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
 
6470
 
 
6471
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
 
6472
                     in_buf, re.icase, re.global))
6535
6473
    {
6536
6474
      /* if the buffer has been reallocated, make adjustements */
6537
6475
      if (save_out_buf != out_buf)
6538
6476
      {
6539
 
        if (save_out_buf == even_buf)
6540
 
          even_buf= out_buf;
 
6477
        if (save_out_buf == r->even_buf)
 
6478
          r->even_buf= out_buf;
6541
6479
        else
6542
 
          odd_buf= out_buf;
 
6480
          r->odd_buf= out_buf;
6543
6481
      }
6544
 
      buf_= out_buf;
 
6482
 
 
6483
      r->buf= out_buf;
6545
6484
      if (in_buf == val)
6546
 
        in_buf= odd_buf;
6547
 
      std::swap(in_buf, out_buf);
6548
 
      buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
 
6485
        in_buf= r->odd_buf;
 
6486
 
 
6487
      std::swap(in_buf,out_buf);
 
6488
 
 
6489
      buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
 
6490
        &r->odd_buf_len;
6549
6491
    }
6550
6492
  }
6551
 
  return buf_ == 0;
 
6493
 
 
6494
  return (r->buf == 0);
6552
6495
}
6553
6496
 
6554
6497
/*
6563
6506
void do_get_replace_regex(struct st_command *command)
6564
6507
{
6565
6508
  char *expr= command->first_argument;
6566
 
  glob_replace_regex.reset(new st_replace_regex(expr));
 
6509
  free_replace_regex();
 
6510
  if (!(glob_replace_regex=init_replace_regex(expr)))
 
6511
    die("Could not init replace_regex");
6567
6512
  command->last_argument= command->end;
6568
6513
}
6569
6514
 
 
6515
void free_replace_regex()
 
6516
{
 
6517
  if (glob_replace_regex)
 
6518
  {
 
6519
    delete_dynamic(&glob_replace_regex->regex_arr);
 
6520
    free(glob_replace_regex->even_buf);
 
6521
    free(glob_replace_regex->odd_buf);
 
6522
    free(glob_replace_regex);
 
6523
    glob_replace_regex=0;
 
6524
  }
 
6525
}
 
6526
 
 
6527
 
 
6528
 
6570
6529
/*
6571
6530
  Performs a regex substitution
6572
6531
 
6630
6589
    /* Repeatedly replace the string with the matched regex */
6631
6590
    string subject(in_string);
6632
6591
    size_t replace_length= strlen(replace);
6633
 
    size_t length_of_replacement= strlen(replace);
6634
6592
    size_t current_position= 0;
6635
6593
    int rc= 0;
6636
 
 
6637
 
    while (true) 
 
6594
    while(0 >= (rc= pcre_exec(re, NULL, subject.c_str() + current_position, subject.length() - current_position,
 
6595
                      0, 0, ovector, 3)))
6638
6596
    {
6639
 
      rc= pcre_exec(re, NULL, subject.c_str(), subject.length(), 
6640
 
                    current_position, 0, ovector, 3);
6641
 
      if (rc < 0)
6642
 
      {
6643
 
        break;
6644
 
      }
6645
 
 
6646
6597
      current_position= static_cast<size_t>(ovector[0]);
6647
6598
      replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6648
 
      subject.replace(current_position, replace_length, replace, length_of_replacement);
6649
 
      current_position= current_position + length_of_replacement;
 
6599
      subject.replace(current_position, replace_length, replace, replace_length);
6650
6600
    }
6651
6601
 
6652
6602
    char *new_buf = (char *) malloc(subject.length() + 1);
6673
6623
#define SET_MALLOC_HUNC 64
6674
6624
#define LAST_CHAR_CODE 259
6675
6625
 
6676
 
class REP_SET
6677
 
{
6678
 
public:
6679
 
  void internal_set_bit(uint32_t bit);
6680
 
  void internal_clear_bit(uint32_t bit);
6681
 
  void or_bits(const REP_SET *from);
6682
 
  void copy_bits(const REP_SET *from);
6683
 
  int cmp_bits(const REP_SET *set2) const;
6684
 
  int get_next_bit(uint32_t lastpos) const;
6685
 
 
 
6626
typedef struct st_rep_set {
6686
6627
  uint32_t  *bits;        /* Pointer to used sets */
6687
6628
  short next[LAST_CHAR_CODE];    /* Pointer to next sets */
6688
6629
  uint32_t  found_len;      /* Best match to date */
6689
6630
  int  found_offset;
6690
6631
  uint32_t  table_offset;
6691
6632
  uint32_t  size_of_bits;      /* For convinience */
6692
 
};
6693
 
 
6694
 
class REP_SETS
6695
 
{
6696
 
public:
6697
 
  int find_set(const REP_SET *find);
6698
 
  void free_last_set();
6699
 
  void free_sets();
6700
 
  void make_sets_invisible();
6701
 
 
 
6633
} REP_SET;
 
6634
 
 
6635
typedef struct st_rep_sets {
6702
6636
  uint32_t    count;      /* Number of sets */
6703
6637
  uint32_t    extra;      /* Extra sets in buffer */
6704
 
  uint32_t    invisible;    /* Sets not shown */
 
6638
  uint32_t    invisible;    /* Sets not chown */
6705
6639
  uint32_t    size_of_bits;
6706
6640
  REP_SET  *set,*set_buffer;
6707
6641
  uint32_t    *bit_buffer;
6708
 
};
 
6642
} REP_SETS;
6709
6643
 
6710
 
struct FOUND_SET 
6711
 
{
 
6644
typedef struct st_found_set {
6712
6645
  uint32_t table_offset;
6713
6646
  int found_offset;
6714
 
};
 
6647
} FOUND_SET;
6715
6648
 
6716
 
struct FOLLOWS
6717
 
{
 
6649
typedef struct st_follow {
6718
6650
  int chr;
6719
6651
  uint32_t table_offset;
6720
6652
  uint32_t len;
6721
 
};
6722
 
 
6723
 
int init_sets(REP_SETS *sets, uint32_t states);
 
6653
} FOLLOWS;
 
6654
 
 
6655
 
 
6656
int init_sets(REP_SETS *sets,uint32_t states);
6724
6657
REP_SET *make_new_set(REP_SETS *sets);
6725
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset);
6726
 
 
6727
 
static uint32_t found_sets= 0;
6728
 
 
6729
 
static uint32_t replace_len(const char *str)
 
6658
void make_sets_invisible(REP_SETS *sets);
 
6659
void free_last_set(REP_SETS *sets);
 
6660
void free_sets(REP_SETS *sets);
 
6661
void internal_set_bit(REP_SET *set, uint32_t bit);
 
6662
void internal_clear_bit(REP_SET *set, uint32_t bit);
 
6663
void or_bits(REP_SET *to,REP_SET *from);
 
6664
void copy_bits(REP_SET *to,REP_SET *from);
 
6665
int cmp_bits(REP_SET *set1,REP_SET *set2);
 
6666
int get_next_bit(REP_SET *set,uint32_t lastpos);
 
6667
int find_set(REP_SETS *sets,REP_SET *find);
 
6668
int find_found(FOUND_SET *found_set,uint32_t table_offset,
 
6669
               int found_offset);
 
6670
uint32_t start_at_word(char * pos);
 
6671
uint32_t end_of_word(char * pos);
 
6672
 
 
6673
static uint32_t found_sets=0;
 
6674
 
 
6675
 
 
6676
static uint32_t replace_len(char * str)
6730
6677
{
6731
6678
  uint32_t len=0;
6732
6679
  while (*str)
6739
6686
  return len;
6740
6687
}
6741
6688
 
6742
 
/* Return 1 if regexp starts with \b or ends with \b*/
6743
 
 
6744
 
static bool start_at_word(const char *pos)
6745
 
{
6746
 
  return ((!memcmp(pos, "\\b",2) && pos[2]) || !memcmp(pos, "\\^", 2));
6747
 
}
6748
 
 
6749
 
static bool end_of_word(const char *pos)
6750
 
{
6751
 
  const char *end= strchr(pos, '\0');
6752
 
  return (end > pos+2 && !memcmp(end-2, "\\b", 2)) || (end >= pos+2 && !memcmp(end-2, "\\$",2));
6753
 
}
6754
 
 
6755
6689
/* Init a replace structure for further calls */
6756
6690
 
6757
 
REPLACE *init_replace(const char **from, const char **to, uint32_t count, char *word_end_chars)
 
6691
REPLACE *init_replace(char * *from, char * *to,uint32_t count,
 
6692
                      char * word_end_chars)
6758
6693
{
6759
 
  const int SPACE_CHAR= 256;
6760
 
  const int START_OF_LINE= 257;
6761
 
  const int END_OF_LINE= 258;
 
6694
  static const int SPACE_CHAR= 256;
 
6695
  static const int START_OF_LINE= 257;
 
6696
  static const int END_OF_LINE= 258;
6762
6697
 
6763
6698
  uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6764
6699
  int used_sets,chr,default_state;
6765
6700
  char used_chars[LAST_CHAR_CODE],is_word_end[256];
6766
 
  char *to_pos, **to_array;
 
6701
  char * pos, *to_pos, **to_array;
 
6702
  REP_SETS sets;
 
6703
  REP_SET *set,*start_states,*word_states,*new_set;
 
6704
  FOLLOWS *follow,*follow_ptr;
 
6705
  REPLACE *replace;
 
6706
  FOUND_SET *found_set;
 
6707
  REPLACE_STRING *rep_str;
 
6708
 
6767
6709
 
6768
6710
  /* Count number of states */
6769
6711
  for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
6783
6725
  for (i=0 ; word_end_chars[i] ; i++)
6784
6726
    is_word_end[(unsigned char) word_end_chars[i]]=1;
6785
6727
 
6786
 
  REP_SETS sets;
6787
 
  REP_SET *set,*start_states,*word_states,*new_set;
6788
 
  REPLACE_STRING *rep_str;
6789
 
  if (init_sets(&sets, states))
6790
 
    return 0;
 
6728
  if (init_sets(&sets,states))
 
6729
    return(0);
6791
6730
  found_sets=0;
6792
 
  vector<FOUND_SET> found_set(max_length * count);
 
6731
  if (!(found_set= (FOUND_SET*) malloc(sizeof(FOUND_SET)*max_length*count)))
 
6732
                                
 
6733
  {
 
6734
    free_sets(&sets);
 
6735
    return(0);
 
6736
  }
6793
6737
  make_new_set(&sets);      /* Set starting set */
6794
 
  sets.make_sets_invisible();      /* Hide previus sets */
 
6738
  make_sets_invisible(&sets);      /* Hide previus sets */
6795
6739
  used_sets=-1;
6796
6740
  word_states=make_new_set(&sets);    /* Start of new word */
6797
6741
  start_states=make_new_set(&sets);    /* This is first state */
6798
 
  vector<FOLLOWS> follow(states + 2);
6799
 
  FOLLOWS *follow_ptr= &follow[1];
 
6742
  if (!(follow=(FOLLOWS*) malloc((states+2)*sizeof(FOLLOWS))))
 
6743
  {
 
6744
    free_sets(&sets);
 
6745
    free(found_set);
 
6746
    return(0);
 
6747
  }
 
6748
 
6800
6749
  /* Init follow_ptr[] */
6801
 
  for (i=0, states=1; i < count; i++)
 
6750
  for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
6802
6751
  {
6803
6752
    if (from[i][0] == '\\' && from[i][1] == '^')
6804
6753
    {
6805
 
      start_states->internal_set_bit(states + 1);
 
6754
      internal_set_bit(start_states,states+1);
6806
6755
      if (!from[i][2])
6807
6756
      {
6808
6757
        start_states->table_offset=i;
6811
6760
    }
6812
6761
    else if (from[i][0] == '\\' && from[i][1] == '$')
6813
6762
    {
6814
 
      start_states->internal_set_bit(states);
6815
 
      word_states->internal_set_bit(states);
 
6763
      internal_set_bit(start_states,states);
 
6764
      internal_set_bit(word_states,states);
6816
6765
      if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6817
6766
      {
6818
6767
        start_states->table_offset=i;
6821
6770
    }
6822
6771
    else
6823
6772
    {
6824
 
      word_states->internal_set_bit(states);
 
6773
      internal_set_bit(word_states,states);
6825
6774
      if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
6826
 
        start_states->internal_set_bit(states + 1);
 
6775
        internal_set_bit(start_states,states+1);
6827
6776
      else
6828
 
        start_states->internal_set_bit(states);
 
6777
        internal_set_bit(start_states,states);
6829
6778
    }
6830
 
    const char *pos;
6831
 
    for (pos= from[i], len=0; *pos ; pos++)
 
6779
    for (pos=from[i], len=0; *pos ; pos++)
6832
6780
    {
6833
6781
      if (*pos == '\\' && *(pos+1))
6834
6782
      {
6871
6819
  }
6872
6820
 
6873
6821
 
6874
 
  for (set_nr=0; set_nr < sets.count ; set_nr++)
 
6822
  for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6875
6823
  {
6876
6824
    set=sets.set+set_nr;
6877
6825
    default_state= 0;        /* Start from beginning */
6878
6826
 
6879
6827
    /* If end of found-string not found or start-set with current set */
6880
6828
 
6881
 
    for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
 
6829
    for (i= UINT32_MAX; (i=get_next_bit(set,i)) ;)
6882
6830
    {
6883
 
      if (!follow[i].chr && !default_state)
6884
 
        default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
 
6831
      if (!follow[i].chr)
 
6832
      {
 
6833
        if (! default_state)
 
6834
          default_state= find_found(found_set,set->table_offset,
 
6835
                                    set->found_offset+1);
 
6836
      }
6885
6837
    }
6886
 
    sets.set[used_sets].copy_bits(set);    /* Save set for changes */
 
6838
    copy_bits(sets.set+used_sets,set);    /* Save set for changes */
6887
6839
    if (!default_state)
6888
 
      sets.set[used_sets].or_bits(sets.set);  /* Can restart from start */
 
6840
      or_bits(sets.set+used_sets,sets.set);  /* Can restart from start */
6889
6841
 
6890
6842
    /* Find all chars that follows current sets */
6891
6843
    memset(used_chars, 0, sizeof(used_chars));
6892
 
    for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i)) ;)
 
6844
    for (i= UINT32_MAX; (i=get_next_bit(sets.set+used_sets,i)) ;)
6893
6845
    {
6894
6846
      used_chars[follow[i].chr]=1;
6895
6847
      if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6899
6851
 
6900
6852
    /* Mark word_chars used if \b is in state */
6901
6853
    if (used_chars[SPACE_CHAR])
6902
 
      for (const char *pos= word_end_chars ; *pos ; pos++)
 
6854
      for (pos= word_end_chars ; *pos ; pos++)
6903
6855
        used_chars[(int) (unsigned char) *pos] = 1;
6904
6856
 
6905
6857
    /* Handle other used characters */
6916
6868
        new_set->found_offset=set->found_offset+1;
6917
6869
        found_end=0;
6918
6870
 
6919
 
        for (i= UINT32_MAX ; (i= sets.set[used_sets].get_next_bit(i)) ; )
 
6871
        for (i= UINT32_MAX ; (i=get_next_bit(sets.set+used_sets,i)) ; )
6920
6872
        {
6921
6873
          if (!follow[i].chr || follow[i].chr == chr ||
6922
6874
              (follow[i].chr == SPACE_CHAR &&
6928
6880
                follow[i].len > found_end)
6929
6881
              found_end=follow[i].len;
6930
6882
            if (chr && follow[i].chr)
6931
 
              new_set->internal_set_bit(i + 1);    /* To next set */
 
6883
              internal_set_bit(new_set,i+1);    /* To next set */
6932
6884
            else
6933
 
              new_set->internal_set_bit(i);
 
6885
              internal_set_bit(new_set,i);
6934
6886
          }
6935
6887
        }
6936
6888
        if (found_end)
6937
6889
        {
6938
6890
          new_set->found_len=0;      /* Set for testing if first */
6939
6891
          bits_set=0;
6940
 
          for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
 
6892
          for (i= UINT32_MAX; (i=get_next_bit(new_set,i)) ;)
6941
6893
          {
6942
6894
            if ((follow[i].chr == SPACE_CHAR ||
6943
6895
                 follow[i].chr == END_OF_LINE) && ! chr)
6947
6899
            if (follow[bit_nr-1].len < found_end ||
6948
6900
                (new_set->found_len &&
6949
6901
                 (chr == 0 || !follow[bit_nr].chr)))
6950
 
              new_set->internal_clear_bit(i);
 
6902
              internal_clear_bit(new_set,i);
6951
6903
            else
6952
6904
            {
6953
6905
              if (chr == 0 || !follow[bit_nr].chr)
6963
6915
          }
6964
6916
          if (bits_set == 1)
6965
6917
          {
6966
 
            set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6967
 
            sets.free_last_set();
 
6918
            set->next[chr] = find_found(found_set,
 
6919
                                        new_set->table_offset,
 
6920
                                        new_set->found_offset);
 
6921
            free_last_set(&sets);
6968
6922
          }
6969
6923
          else
6970
 
            set->next[chr] = sets.find_set(new_set);
 
6924
            set->next[chr] = find_set(&sets,new_set);
6971
6925
        }
6972
6926
        else
6973
 
          set->next[chr] = sets.find_set(new_set);
 
6927
          set->next[chr] = find_set(&sets,new_set);
6974
6928
      }
6975
6929
    }
6976
6930
  }
6977
6931
 
6978
6932
  /* Alloc replace structure for the replace-state-machine */
6979
6933
 
6980
 
  REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
 
    + sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
6982
 
  if (replace)
 
6934
  if ((replace=(REPLACE*) malloc(sizeof(REPLACE)*(sets.count)+
 
6935
                                 sizeof(REPLACE_STRING)*(found_sets+1)+
 
6936
                                 sizeof(char *)*count+result_len)))
6983
6937
  {
6984
6938
    memset(replace, 0, sizeof(REPLACE)*(sets.count)+
6985
6939
                       sizeof(REPLACE_STRING)*(found_sets+1)+
6996
6950
    rep_str[0].replace_string=0;
6997
6951
    for (i=1 ; i <= found_sets ; i++)
6998
6952
    {
6999
 
      const char *pos= from[found_set[i-1].table_offset];
 
6953
      pos=from[found_set[i-1].table_offset];
7000
6954
      rep_str[i].found= !memcmp(pos, "\\^", 3) ? 2 : 1;
7001
 
      rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
7002
 
      rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
7003
 
      rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
 
6955
      rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
 
6956
      rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
 
6957
      rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
 
6958
        end_of_word(pos);
7004
6959
    }
7005
6960
    for (i=0 ; i < sets.count ; i++)
7006
6961
    {
7011
6966
          replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7012
6967
    }
7013
6968
  }
7014
 
  sets.free_sets();
7015
 
  return replace;
 
6969
  free(follow);
 
6970
  free_sets(&sets);
 
6971
  free(found_set);
 
6972
  return(replace);
7016
6973
}
7017
6974
 
7018
6975
 
7033
6990
 
7034
6991
/* Make help sets invisible for nicer codeing */
7035
6992
 
7036
 
void REP_SETS::make_sets_invisible()
 
6993
void make_sets_invisible(REP_SETS *sets)
7037
6994
{
7038
 
  invisible= count;
7039
 
  set += count;
7040
 
  count= 0;
 
6995
  sets->invisible=sets->count;
 
6996
  sets->set+=sets->count;
 
6997
  sets->count=0;
7041
6998
}
7042
6999
 
7043
7000
REP_SET *make_new_set(REP_SETS *sets)
7075
7032
  return make_new_set(sets);
7076
7033
}
7077
7034
 
7078
 
void REP_SETS::free_last_set()
7079
 
{
7080
 
  count--;
7081
 
  extra++;
7082
 
}
7083
 
 
7084
 
void REP_SETS::free_sets()
7085
 
{
7086
 
  free(set_buffer);
7087
 
  free(bit_buffer);
7088
 
}
7089
 
 
7090
 
void REP_SET::internal_set_bit(uint32_t bit)
7091
 
{
7092
 
  bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
7093
 
}
7094
 
 
7095
 
void REP_SET::internal_clear_bit(uint32_t bit)
7096
 
{
7097
 
  bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
7098
 
}
7099
 
 
7100
 
 
7101
 
void REP_SET::or_bits(const REP_SET *from)
7102
 
{
7103
 
  for (uint32_t i= 0 ; i < size_of_bits; i++)
7104
 
    bits[i]|=from->bits[i];
7105
 
}
7106
 
 
7107
 
void REP_SET::copy_bits(const REP_SET *from)
7108
 
{
7109
 
  memcpy(bits, from->bits, sizeof(uint32_t) * size_of_bits);
7110
 
}
7111
 
 
7112
 
int REP_SET::cmp_bits(const REP_SET *set2) const
7113
 
{
7114
 
  return memcmp(bits, set2->bits, sizeof(uint32_t) * size_of_bits);
7115
 
}
 
7035
void free_last_set(REP_SETS *sets)
 
7036
{
 
7037
  sets->count--;
 
7038
  sets->extra++;
 
7039
  return;
 
7040
}
 
7041
 
 
7042
void free_sets(REP_SETS *sets)
 
7043
{
 
7044
  free(sets->set_buffer);
 
7045
  free(sets->bit_buffer);
 
7046
  return;
 
7047
}
 
7048
 
 
7049
void internal_set_bit(REP_SET *set, uint32_t bit)
 
7050
{
 
7051
  set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
 
7052
  return;
 
7053
}
 
7054
 
 
7055
void internal_clear_bit(REP_SET *set, uint32_t bit)
 
7056
{
 
7057
  set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
 
7058
  return;
 
7059
}
 
7060
 
 
7061
 
 
7062
void or_bits(REP_SET *to,REP_SET *from)
 
7063
{
 
7064
  register uint32_t i;
 
7065
  for (i=0 ; i < to->size_of_bits ; i++)
 
7066
    to->bits[i]|=from->bits[i];
 
7067
  return;
 
7068
}
 
7069
 
 
7070
void copy_bits(REP_SET *to,REP_SET *from)
 
7071
{
 
7072
  memcpy(to->bits,from->bits,
 
7073
         (size_t) (sizeof(uint32_t) * to->size_of_bits));
 
7074
}
 
7075
 
 
7076
int cmp_bits(REP_SET *set1,REP_SET *set2)
 
7077
{
 
7078
  return memcmp(set1->bits,set2->bits, sizeof(uint32_t) * set1->size_of_bits);
 
7079
}
 
7080
 
7116
7081
 
7117
7082
/* Get next set bit from set. */
7118
7083
 
7119
 
int REP_SET::get_next_bit(uint32_t lastpos) const
 
7084
int get_next_bit(REP_SET *set,uint32_t lastpos)
7120
7085
{
7121
 
  uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
7122
 
  uint32_t *end= bits + size_of_bits;
7123
 
  uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
7124
 
 
7125
 
  while (!bits0 && ++start < end)
7126
 
    bits0= start[0];
7127
 
  if (!bits0)
 
7086
  uint32_t pos,*start,*end,bits;
 
7087
 
 
7088
  start=set->bits+ ((lastpos+1) / WORD_BIT);
 
7089
  end=set->bits + set->size_of_bits;
 
7090
  bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
 
7091
 
 
7092
  while (! bits && ++start < end)
 
7093
    bits=start[0];
 
7094
  if (!bits)
7128
7095
    return 0;
7129
 
  uint32_t pos= (start - bits) * WORD_BIT;
7130
 
  while (!(bits0 & 1))
 
7096
  pos=(uint32_t) (start-set->bits)*WORD_BIT;
 
7097
  while (! (bits & 1))
7131
7098
  {
7132
 
    bits0 >>=1;
 
7099
    bits>>=1;
7133
7100
    pos++;
7134
7101
  }
7135
7102
  return pos;
7139
7106
   free given set, else put in given set in sets and return its
7140
7107
   position */
7141
7108
 
7142
 
int REP_SETS::find_set(const REP_SET *find)
 
7109
int find_set(REP_SETS *sets,REP_SET *find)
7143
7110
{
7144
 
  uint32_t i= 0;
7145
 
  for (; i < count - 1; i++)
 
7111
  uint32_t i;
 
7112
  for (i=0 ; i < sets->count-1 ; i++)
7146
7113
  {
7147
 
    if (!set[i].cmp_bits(find))
 
7114
    if (!cmp_bits(sets->set+i,find))
7148
7115
    {
7149
 
      free_last_set();
 
7116
      free_last_set(sets);
7150
7117
      return i;
7151
7118
    }
7152
7119
  }
7160
7127
   set->next[] == -1 is reserved for end without replaces.
7161
7128
*/
7162
7129
 
7163
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
 
7130
int find_found(FOUND_SET *found_set,uint32_t table_offset, int found_offset)
7164
7131
{
7165
 
  uint32_t i= 0;
7166
 
  for (; i < found_sets; i++)
7167
 
  {
 
7132
  int i;
 
7133
  for (i=0 ; (uint32_t) i < found_sets ; i++)
7168
7134
    if (found_set[i].table_offset == table_offset &&
7169
7135
        found_set[i].found_offset == found_offset)
7170
 
      return - i - 2;
7171
 
  }
7172
 
  found_set[i].table_offset= table_offset;
7173
 
  found_set[i].found_offset= found_offset;
 
7136
      return -i-2;
 
7137
  found_set[i].table_offset=table_offset;
 
7138
  found_set[i].found_offset=found_offset;
7174
7139
  found_sets++;
7175
 
  return - i - 2; // return new postion
 
7140
  return -i-2;        /* return new postion */
 
7141
}
 
7142
 
 
7143
/* Return 1 if regexp starts with \b or ends with \b*/
 
7144
 
 
7145
uint32_t start_at_word(char * pos)
 
7146
{
 
7147
  return (((!memcmp(pos, "\\b",2) && pos[2]) ||
 
7148
           !memcmp(pos, "\\^", 2)) ? 1 : 0);
 
7149
}
 
7150
 
 
7151
uint32_t end_of_word(char * pos)
 
7152
{
 
7153
  char * end= strchr(pos, '\0');
 
7154
  return ((end > pos+2 && !memcmp(end-2, "\\b", 2)) ||
 
7155
          (end >= pos+2 && !memcmp(end-2, "\\$",2))) ? 1 : 0;
7176
7156
}
7177
7157
 
7178
7158
/****************************************************************************
7251
7231
} /* insert_pointer_name */
7252
7232
 
7253
7233
 
 
7234
/* free pointer array */
 
7235
 
 
7236
void free_pointer_array(POINTER_ARRAY *pa)
 
7237
{
 
7238
  if (pa->typelib.count)
 
7239
  {
 
7240
    pa->typelib.count=0;
 
7241
    free((char*) pa->typelib.type_names);
 
7242
    pa->typelib.type_names=0;
 
7243
    free(pa->str);
 
7244
  }
 
7245
} /* free_pointer_array */
 
7246
 
 
7247
 
7254
7248
/* Functions that uses replace and replace_regex */
7255
7249
 
7256
7250
/* Append the string to ds, with optional replace */
7257
 
void replace_append_mem(string *ds, const char *val, int len)
 
7251
void replace_append_mem(string *ds,
 
7252
                        const char *val, int len)
7258
7253
{
7259
7254
  char *v= strdup(val);
7260
7255
 
7261
 
  if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
 
7256
  if (glob_replace_regex)
7262
7257
  {
7263
 
    v= glob_replace_regex->buf_;
7264
 
    len= strlen(v);
 
7258
    /* Regex replace */
 
7259
    if (!multi_reg_replace(glob_replace_regex, v))
 
7260
    {
 
7261
      v= glob_replace_regex->buf;
 
7262
      len= strlen(v);
 
7263
    }
7265
7264
  }
 
7265
 
7266
7266
  if (glob_replace)
7267
7267
  {
7268
7268
    /* Normal replace */
7269
7269
    replace_strings_append(glob_replace, ds, v, len);
7270
7270
  }
7271
7271
  else
 
7272
  {
7272
7273
    ds->append(v, len);
 
7274
  }
7273
7275
}
7274
7276
 
7275
7277
 
7338
7340
 
7339
7341
  return;
7340
7342
}
7341
 
 
7342
 
static void free_all_replace()
7343
 
{
7344
 
  free_replace();
7345
 
  glob_replace_regex.reset();
7346
 
  free_replace_column();
7347
 
}