~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzletest.cc

few updates and modifications to admin commands

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
#include <sys/stat.h>
57
57
#include <sys/types.h>
58
58
#include <fcntl.h>
59
 
#include <boost/array.hpp>
60
 
#include <boost/foreach.hpp>
61
59
#include <boost/program_options.hpp>
62
 
#include <boost/smart_ptr.hpp>
63
60
 
64
61
#include PCRE_HEADER
65
62
 
66
63
#include <stdarg.h>
67
64
#include <boost/unordered_map.hpp>
68
65
 
 
66
#include "errname.h"
 
67
 
69
68
/* 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>
 
69
#include "drizzled/gettext.h"
 
70
#include "drizzled/drizzle_time.h"
 
71
#include "drizzled/charset.h"
74
72
#include <drizzled/configmake.h>
75
73
 
76
 
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
77
 
 
78
74
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
75
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
80
76
#endif
94
90
#define QUERY_SEND_FLAG  1
95
91
#define QUERY_REAP_FLAG  2
96
92
 
97
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
98
93
ErrorCodes global_error_names;
99
94
 
100
95
enum {
121
116
static bool is_windows= false;
122
117
static bool use_drizzle_protocol= false;
123
118
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
124
 
static void free_all_replace();
125
119
 
126
120
std::string opt_basedir,
127
121
  opt_charsets_dir,
171
165
  uint32_t lineno; /* Current line in file */
172
166
};
173
167
 
174
 
static boost::array<st_test_file, 16> file_stack;
175
 
static st_test_file* cur_file;
 
168
static struct st_test_file file_stack[16];
 
169
static struct st_test_file* cur_file;
 
170
static struct st_test_file* file_stack_end;
 
171
 
176
172
 
177
173
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
178
174
 
182
178
*/
183
179
static char *timer_file = NULL;
184
180
static uint64_t timer_start;
185
 
static void timer_output();
186
 
static uint64_t timer_now();
 
181
static void timer_output(void);
 
182
static uint64_t timer_now(void);
187
183
 
188
184
static uint64_t progress_start= 0;
189
185
 
204
200
 
205
201
/* if set, all results are concated and compared against this file */
206
202
 
207
 
class VAR
 
203
typedef struct st_var
208
204
{
209
 
public:
210
205
  char *name;
211
206
  int name_len;
212
207
  char *str_val;
216
211
  int int_dirty; /* do not update string if int is updated until first read */
217
212
  int alloced;
218
213
  char *env_s;
219
 
};
 
214
} VAR;
220
215
 
221
216
/*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;
 
217
VAR var_reg[10];
 
218
 
 
219
 
 
220
boost::unordered_map<string, VAR *> var_hash;
226
221
 
227
222
struct st_connection
228
223
{
395
390
  struct st_match_err err[10];
396
391
  uint32_t count;
397
392
};
398
 
 
399
 
static st_expected_errors saved_expected_errors;
400
 
 
401
 
class st_command
 
393
static struct st_expected_errors saved_expected_errors;
 
394
 
 
395
struct st_command
402
396
{
403
 
public:
404
397
  char *query, *query_buf,*first_argument,*last_argument,*end;
405
398
  int first_word_len, query_len;
406
399
  bool abort_on_error;
407
400
  st_expected_errors expected_errors;
408
401
  string require_file;
409
 
  enum_commands type;
 
402
  enum enum_commands type;
410
403
 
411
404
  st_command()
412
405
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
418
411
 
419
412
  ~st_command()
420
413
  {
421
 
    free(query_buf);
 
414
    if (query_buf != NULL)
 
415
    {
 
416
      free(query_buf);
 
417
    }
422
418
  }
423
419
};
424
420
 
443
439
VAR* var_from_env(const char *, const char *);
444
440
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
445
441
              int val_len);
 
442
void var_free(pair<string, VAR*> v);
446
443
VAR* var_get(const char *var_name, const char** var_name_end,
447
444
             bool raw, bool ignore_not_existing);
448
445
void eval_expr(VAR* v, const char *p, const char** p_end);
449
446
bool match_delimiter(int c, const char *delim, uint32_t length);
450
447
void dump_result_to_reject_file(char *buf, int size);
451
448
void dump_result_to_log_file(const char *buf, int size);
452
 
void dump_warning_messages();
453
 
void dump_progress();
 
449
void dump_warning_messages(void);
 
450
void dump_progress(void);
454
451
 
455
452
void do_eval(string *query_eval, const char *query,
456
453
             const char *query_end, bool pass_through_escape_chars);
461
458
static char *replace_column[MAX_COLUMNS];
462
459
static uint32_t max_replace_column= 0;
463
460
void do_get_replace_column(struct st_command*);
464
 
void free_replace_column();
 
461
void free_replace_column(void);
465
462
 
466
463
/* For replace */
467
464
void do_get_replace(struct st_command *command);
468
 
void free_replace();
 
465
void free_replace(void);
469
466
 
470
467
/* For replace_regex */
471
468
void do_get_replace_regex(struct st_command *command);
 
469
void free_replace_regex(void);
 
470
 
 
471
 
 
472
void free_all_replace(void);
 
473
 
 
474
 
 
475
void free_all_replace(void){
 
476
  free_replace();
 
477
  free_replace_regex();
 
478
  free_replace_column();
 
479
}
472
480
 
473
481
void replace_append_mem(string *ds, const char *val,
474
482
                        int len);
485
493
void do_eval(string *query_eval, const char *query,
486
494
             const char *query_end, bool pass_through_escape_chars)
487
495
{
488
 
  char c, next_c;
489
 
  int escaped = 0;
 
496
  const char *p;
 
497
  register char c, next_c;
 
498
  register int escaped = 0;
490
499
  VAR *v;
491
500
 
492
 
  for (const char *p= query; (c= *p) && p < query_end; ++p)
 
501
 
 
502
  for (p= query; (c= *p) && p < query_end; ++p)
493
503
  {
494
504
    switch(c) {
495
505
    case '$':
834
844
 
835
845
static void handle_command_error(struct st_command *command, uint32_t error)
836
846
{
 
847
 
837
848
  if (error != 0)
838
849
  {
839
850
    uint32_t i;
860
871
        command->first_word_len, command->query,
861
872
        command->expected_errors.err[0].code.errnum);
862
873
  }
 
874
  return;
863
875
}
864
876
 
865
877
 
866
 
static void close_connections()
 
878
static void close_connections(void)
867
879
{
868
880
  for (--next_con; next_con >= connections; --next_con)
869
881
  {
874
886
    }
875
887
    free(next_con->name);
876
888
  }
 
889
  return;
877
890
}
878
891
 
879
892
 
880
 
static void close_files()
 
893
static void close_files(void)
881
894
{
882
 
  for (; cur_file >= file_stack.data(); cur_file--)
 
895
 
 
896
  for (; cur_file >= file_stack; cur_file--)
883
897
  {
884
898
    if (cur_file->file && cur_file->file != stdin)
 
899
    {
885
900
      fclose(cur_file->file);
886
 
    free(const_cast<char*>(cur_file->file_name));
 
901
    }
 
902
    free((unsigned char*) cur_file->file_name);
887
903
    cur_file->file_name= 0;
888
904
  }
 
905
  return;
889
906
}
890
907
 
891
 
static void free_used_memory()
 
908
 
 
909
static void free_used_memory(void)
892
910
{
 
911
  uint32_t i;
 
912
 
 
913
 
893
914
  close_connections();
894
915
  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
 
  }
 
916
  for_each(var_hash.begin(), var_hash.end(), var_free);
902
917
  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++)
 
918
 
 
919
  vector<st_command *>::iterator iter;
 
920
  for (iter= q_lines.begin() ; iter < q_lines.end() ; iter++)
 
921
  {
 
922
    struct st_command * q_line= *iter;
 
923
    delete q_line;
 
924
  }
 
925
 
 
926
  for (i= 0; i < 10; i++)
906
927
  {
907
928
    if (var_reg[i].alloced_len)
908
929
      free(var_reg[i].str_val);
909
930
  }
 
931
 
910
932
  free_all_replace();
911
933
  free(opt_pass);
 
934
 
 
935
  return;
912
936
}
913
937
 
914
938
 
933
957
      assert(0);
934
958
    }
935
959
  }
 
960
 
936
961
  exit(exit_code);
937
962
}
938
963
 
952
977
 
953
978
  /* Print the error message */
954
979
  fprintf(stderr, "drizzletest: ");
955
 
  if (cur_file && cur_file != file_stack.data())
 
980
  if (cur_file && cur_file != file_stack)
956
981
    fprintf(stderr, "In included file \"%s\": ",
957
982
            cur_file->file_name);
958
983
  if (start_lineno > 0)
1013
1038
 
1014
1039
  /* Print include filestack */
1015
1040
  fprintf(stderr, "The test '%s' is not supported by this installation\n",
1016
 
          file_stack[0].file_name);
 
1041
          file_stack->file_name);
1017
1042
  fprintf(stderr, "Detected in file %s at line %d\n",
1018
1043
          err_file->file_name, err_file->lineno);
1019
 
  while (err_file != file_stack.data())
 
1044
  while (err_file != file_stack)
1020
1045
  {
1021
1046
    err_file--;
1022
1047
    fprintf(stderr, "included from %s at line %d\n",
1047
1072
 
1048
1073
  va_start(args, fmt);
1049
1074
  fprintf(stderr, "drizzletest: ");
1050
 
  if (cur_file && cur_file != file_stack.data())
 
1075
  if (cur_file && cur_file != file_stack)
1051
1076
    fprintf(stderr, "In included file \"%s\": ",
1052
1077
            cur_file->file_name);
1053
1078
  if (start_lineno != 0)
1055
1080
  vfprintf(stderr, fmt, args);
1056
1081
  fprintf(stderr, "\n");
1057
1082
  va_end(args);
 
1083
 
 
1084
  return;
1058
1085
}
1059
1086
 
1060
1087
 
1070
1097
  if (start_lineno != 0)
1071
1098
  {
1072
1099
    ds_warning_messages.append("Warning detected ");
1073
 
    if (cur_file && cur_file != file_stack.data())
 
1100
    if (cur_file && cur_file != file_stack)
1074
1101
    {
1075
1102
      len= snprintf(buff, sizeof(buff), "in included file %s ",
1076
1103
                    cur_file->file_name);
1435
1462
  int fd;
1436
1463
  char temp_file_path[FN_REFLEN];
1437
1464
 
1438
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
 
1465
  if ((fd= internal::create_temp_file(temp_file_path, NULL,
1439
1466
                            "tmp", MYF(MY_WME))) < 0)
1440
1467
    die("Failed to create temporary file for ds");
1441
1468
 
1603
1630
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1604
1631
              int val_len)
1605
1632
{
 
1633
  int val_alloc_len;
 
1634
  VAR *tmp_var;
1606
1635
  if (!name_len && name)
1607
1636
    name_len = strlen(name);
1608
1637
  if (!val_len && val)
1609
1638
    val_len = strlen(val) ;
1610
 
  VAR *tmp_var = v ? v : (VAR*)malloc(sizeof(*tmp_var) + name_len+1);
 
1639
  val_alloc_len = val_len + 16; /* room to grow */
 
1640
  if (!(tmp_var=v) && !(tmp_var = (VAR*)malloc(sizeof(*tmp_var)
 
1641
                                               + name_len+1)))
 
1642
    die("Out of memory");
1611
1643
 
1612
 
  tmp_var->name = name ? (char*)&tmp_var[1] : 0;
 
1644
  tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
1613
1645
  tmp_var->alloced = (v == 0);
1614
1646
 
1615
 
  int val_alloc_len = val_len + 16; /* room to grow */
1616
 
  tmp_var->str_val = (char*)malloc(val_alloc_len+1);
 
1647
  if (!(tmp_var->str_val = (char *)malloc(val_alloc_len+1)))
 
1648
    die("Out of memory");
1617
1649
 
1618
1650
  memcpy(tmp_var->name, name, name_len);
1619
1651
  if (val)
1624
1656
  tmp_var->name_len = name_len;
1625
1657
  tmp_var->str_val_len = val_len;
1626
1658
  tmp_var->alloced_len = val_alloc_len;
1627
 
  tmp_var->int_val = val ? atoi(val) : 0;
1628
 
  tmp_var->int_dirty = false;
 
1659
  tmp_var->int_val = (val) ? atoi(val) : 0;
 
1660
  tmp_var->int_dirty = 0;
1629
1661
  tmp_var->env_s = 0;
1630
1662
  return tmp_var;
1631
1663
}
1632
1664
 
 
1665
 
 
1666
void var_free(pair<string, VAR *> v)
 
1667
{
 
1668
  free(v.second->str_val);
 
1669
  free(v.second->env_s);
 
1670
  if (v.second->alloced)
 
1671
    free(v.second);
 
1672
}
 
1673
 
 
1674
 
1633
1675
VAR* var_from_env(const char *name, const char *def_val)
1634
1676
{
1635
 
  const char *tmp= getenv(name);
1636
 
  if (!tmp)
 
1677
  const char *tmp;
 
1678
  VAR *v;
 
1679
  if (!(tmp = getenv(name)))
1637
1680
    tmp = def_val;
1638
 
  return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1681
 
 
1682
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1683
  string var_name(name);
 
1684
  var_hash.insert(make_pair(var_name, v));
 
1685
  return v;
1639
1686
}
1640
1687
 
 
1688
 
1641
1689
VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
1642
1690
             bool ignore_not_existing)
1643
1691
{
1644
1692
  int digit;
1645
1693
  VAR *v;
 
1694
 
1646
1695
  if (*var_name != '$')
1647
1696
    goto err;
1648
1697
  digit = *++var_name - '0';
1664
1713
      die("Too long variable name: %s", save_var_name);
1665
1714
 
1666
1715
    string save_var_name_str(save_var_name, length);
1667
 
    var_hash_t::iterator iter= var_hash.find(save_var_name_str);
 
1716
    boost::unordered_map<string, VAR*>::iterator iter=
 
1717
      var_hash.find(save_var_name_str);
1668
1718
    if (iter == var_hash.end())
1669
1719
    {
1670
1720
      char buff[MAX_VAR_NAME_LENGTH+1];
1674
1724
    }
1675
1725
    else
1676
1726
    {
1677
 
      v= iter->second;
 
1727
      v= (*iter).second;
1678
1728
    }
1679
1729
    var_name--;  /* Point at last character */
1680
1730
  }
1681
1731
  else
1682
 
    v = &var_reg[digit];
 
1732
    v = var_reg + digit;
1683
1733
 
1684
1734
  if (!raw && v->int_dirty)
1685
1735
  {
1701
1751
static VAR *var_obtain(const char *name, int len)
1702
1752
{
1703
1753
  string var_name(name, len);
1704
 
  var_hash_t::iterator iter= var_hash.find(var_name);
 
1754
  boost::unordered_map<string, VAR*>::iterator iter=
 
1755
    var_hash.find(var_name);
1705
1756
  if (iter != var_hash.end())
1706
 
    return iter->second;
1707
 
  return var_hash[var_name] = var_init(0, name, len, "", 0);
 
1757
    return (*iter).second;
 
1758
  VAR *v = var_init(0, name, len, "", 0);
 
1759
  var_hash.insert(make_pair(var_name, v));
 
1760
  return v;
1708
1761
}
1709
1762
 
1710
1763
 
1731
1784
    v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
1732
1785
  }
1733
1786
  else
1734
 
    v= &var_reg[digit];
 
1787
    v= var_reg + digit;
1735
1788
 
1736
1789
  eval_expr(v, var_val, (const char**) &var_val_end);
1737
1790
 
2015
2068
    eval_expr(var, value, 0);
2016
2069
  }
2017
2070
  drizzle_result_free(&res);
 
2071
 
 
2072
  return;
2018
2073
}
2019
2074
 
2020
2075
 
2045
2100
{
2046
2101
  if (*p == '$')
2047
2102
  {
2048
 
    VAR *vp= var_get(p, p_end, 0, 0);
2049
 
    if (vp)
 
2103
    VAR *vp;
 
2104
    if ((vp= var_get(p, p_end, 0, 0)))
2050
2105
      var_copy(v, vp);
2051
2106
    return;
2052
2107
  }
2107
2162
  }
2108
2163
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2109
2164
 
 
2165
  if (cur_file == file_stack_end)
 
2166
    die("Source directives are nesting too deep");
2110
2167
  cur_file++;
2111
 
  if (cur_file == &*file_stack.end())
2112
 
    die("Source directives are nesting too deep");
2113
2168
  if (!(cur_file->file= fopen(buff, "r")))
2114
2169
  {
2115
2170
    cur_file--;
2171
2226
}
2172
2227
 
2173
2228
 
2174
 
static void init_builtin_echo()
 
2229
static void init_builtin_echo(void)
2175
2230
{
2176
2231
  builtin_echo[0]= 0;
 
2232
  return;
2177
2233
}
2178
2234
 
2179
2235
 
2425
2481
 
2426
2482
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
2427
2483
  handle_command_error(command, error);
 
2484
  return;
2428
2485
}
2429
2486
 
2430
2487
 
2459
2516
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2460
2517
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2461
2518
  handle_command_error(command, error);
 
2519
  return;
2462
2520
}
2463
2521
 
2464
2522
 
2496
2554
    die("You must write a 4 digit octal number for mode");
2497
2555
 
2498
2556
  handle_command_error(command, chmod(ds_file.c_str(), mode));
 
2557
  return;
2499
2558
}
2500
2559
 
2501
2560
 
2525
2584
 
2526
2585
  error= (access(ds_filename.c_str(), F_OK) != 0);
2527
2586
  handle_command_error(command, error);
 
2587
  return;
2528
2588
}
2529
2589
 
2530
2590
 
2553
2613
 
2554
2614
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
2555
2615
  handle_command_error(command, error);
 
2616
  return;
2556
2617
}
2557
2618
 
2558
2619
/*
2580
2641
 
2581
2642
  error= rmdir(ds_dirname.c_str()) != 0;
2582
2643
  handle_command_error(command, error);
 
2644
  return;
2583
2645
}
2584
2646
 
2585
2647
 
2818
2880
  }
2819
2881
 
2820
2882
  handle_command_error(command, error);
 
2883
  return;
2821
2884
}
2822
2885
 
2823
2886
 
2867
2930
 
2868
2931
  if (drizzle_quit(&con->con,&result, &ret))
2869
2932
    drizzle_result_free(&result);
 
2933
 
 
2934
  return;
2870
2935
}
2871
2936
 
2872
2937
 
2963
3028
  internal::my_delete(temp_file_path, MYF(0));
2964
3029
 
2965
3030
  handle_command_error(command, WEXITSTATUS(error));
 
3031
  return;
2966
3032
}
2967
3033
 
2968
3034
 
3136
3202
  when ndb binlog is on, this call will wait until last updated epoch
3137
3203
  (locally in the drizzled) has been received into the binlog
3138
3204
*/
3139
 
static int do_save_master_pos()
 
3205
static int do_save_master_pos(void)
3140
3206
{
3141
3207
  drizzle_result_st res;
3142
3208
  drizzle_return_t ret;
3275
3341
    sleep_val= opt_sleep;
3276
3342
 
3277
3343
  if (sleep_val)
3278
 
    usleep(sleep_val * 1000000);
 
3344
    usleep((uint32_t) (sleep_val * 1000000L));
3279
3345
  command->last_argument= sleep_end;
3280
3346
  return 0;
3281
3347
}
3282
3348
 
3283
3349
 
3284
 
static void do_get_file_name(st_command *command, string &dest)
 
3350
static void do_get_file_name(struct st_command *command, string &dest)
3285
3351
{
3286
 
  char *p= command->first_argument;
 
3352
  char *p= command->first_argument, *name;
3287
3353
  if (!*p)
3288
3354
    die("Missing file name argument");
3289
 
  char *name= p;
 
3355
  name= p;
3290
3356
  while (*p && !my_isspace(charset_info,*p))
3291
3357
    p++;
3292
3358
  if (*p)
3321
3387
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3322
3388
}
3323
3389
 
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
3390
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3380
3391
{
3381
3392
  size_t err_name_len= error_end - error_name;
3382
3393
  string error_name_s(error_name, err_name_len);
3383
3394
 
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;
 
3395
  uint32_t code= global_error_names.getErrorCode(error_name_s);
 
3396
 
 
3397
  if (!code)
 
3398
    die("Unknown SQL error name '%s'", error_name_s.c_str());
 
3399
 
 
3400
  return(code);
3390
3401
}
3391
3402
 
3392
3403
static void do_get_errcodes(struct st_command *command)
3454
3465
    {
3455
3466
      die("The error name definition must start with an uppercase E");
3456
3467
    }
3457
 
    else if (*p == 'H')
 
3468
    else
3458
3469
    {
3459
 
      /* Error name string */
3460
 
 
3461
 
      to->code.errnum= get_errcode_from_name(p, end);
 
3470
      long val;
 
3471
      char *start= p;
 
3472
      /* Check that the string passed to str2int only contain digits */
 
3473
      while (*p && p != end)
 
3474
      {
 
3475
        if (!my_isdigit(charset_info, *p))
 
3476
          die("Invalid argument to error: '%s' - "              \
 
3477
              "the errno may only consist of digits[0-9]",
 
3478
              command->first_argument);
 
3479
        p++;
 
3480
      }
 
3481
 
 
3482
      /* Convert the sting to int */
 
3483
      istringstream buff(start);
 
3484
      if ((buff >> val).fail())
 
3485
        die("Invalid argument to error: '%s'", command->first_argument);
 
3486
 
 
3487
      to->code.errnum= (uint32_t) val;
3462
3488
      to->type= ERR_ERRNO;
3463
3489
    }
3464
 
    else
3465
 
    {
3466
 
      die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3467
 
    }
3468
3490
    to++;
3469
3491
    count++;
3470
3492
 
4004
4026
{
4005
4027
  char *p= command->first_argument;
4006
4028
  const char *expr_start, *expr_end;
 
4029
  VAR v;
4007
4030
  const char *cmd_name= (cmd == cmd_while ? "while" : "if");
4008
4031
  bool not_expr= false;
4009
4032
 
4046
4069
  if (*p && *p != '{')
4047
4070
    die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
4048
4071
 
4049
 
  VAR v;
4050
4072
  var_init(&v,0,0,0,0);
4051
4073
  eval_expr(&v, expr_start, &expr_end);
4052
4074
 
4182
4204
      }
4183
4205
      free((unsigned char*) cur_file->file_name);
4184
4206
      cur_file->file_name= 0;
4185
 
      if (cur_file == file_stack.data())
 
4207
      if (cur_file == file_stack)
4186
4208
      {
4187
4209
        /* We're back at the first file, check if
4188
4210
           all { have matching }
4416
4438
        end++;
4417
4439
      save= *end;
4418
4440
      *end= 0;
4419
 
      type= command_typelib.find_type(start, 1+2);
 
4441
      type= find_type(start, &command_typelib, 1+2);
4420
4442
      if (type)
4421
4443
        warning_msg("Embedded drizzletest command '--%s' detected in "
4422
4444
                    "query '%s' was this intentional? ",
4622
4644
          log_file);
4623
4645
}
4624
4646
 
4625
 
void dump_progress()
 
4647
void dump_progress(void)
4626
4648
{
4627
4649
  char progress_file[FN_REFLEN];
4628
4650
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4632
4654
              ds_progress.c_str(), ds_progress.length());
4633
4655
}
4634
4656
 
4635
 
void dump_warning_messages()
 
4657
void dump_warning_messages(void)
4636
4658
{
4637
4659
  char warn_file[FN_REFLEN];
4638
4660
 
4697
4719
    for (i = 0; i < num_fields; i++)
4698
4720
    {
4699
4721
      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
 
      }
 
4722
      append_field(ds, i, column,
 
4723
                   (const char*)row[i], lengths[i], !row[i]);
4730
4724
    }
4731
4725
    if (!display_result_vertically)
4732
4726
      ds->append("\n");
4770
4764
    ds->append("\t", 1);
4771
4765
    replace_append_uint(ds, drizzle_column_size(column));
4772
4766
    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
 
    }
 
4767
    replace_append_uint(ds, drizzle_column_max_size(column));
4781
4768
    ds->append("\t", 1);
4782
4769
    ds->append((char*) ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL) ? "N" : "Y"), 1);
4783
4770
    ds->append("\t", 1);
5274
5261
 
5275
5262
  save= command->query[command->first_word_len];
5276
5263
  command->query[command->first_word_len]= 0;
5277
 
  type= command_typelib.find_type(command->query, 1+2);
 
5264
  type= find_type(command->query, &command_typelib, 1+2);
5278
5265
  command->query[command->first_word_len]= save;
5279
5266
  if (type > 0)
5280
5267
  {
5318
5305
        */
5319
5306
        save= command->query[command->first_word_len-1];
5320
5307
        command->query[command->first_word_len-1]= 0;
5321
 
        if (command_typelib.find_type(command->query, 1+2) > 0)
 
5308
        if (find_type(command->query, &command_typelib, 1+2) > 0)
5322
5309
          die("Extra delimiter \";\" found");
5323
5310
        command->query[command->first_word_len-1]= save;
5324
5311
 
5492
5479
 
5493
5480
  if (user_config_dir.compare(0, 2, "~/") == 0)
5494
5481
  {
5495
 
    const char *homedir= getenv("HOME");
 
5482
    char *homedir;
 
5483
    homedir= getenv("HOME");
5496
5484
    if (homedir != NULL)
5497
5485
      user_config_dir.replace(0, 1, homedir);
5498
5486
  }
5539
5527
  next_con= connections + 1;
5540
5528
 
5541
5529
  /* Init file stack */
5542
 
  memset(file_stack.data(), 0, sizeof(file_stack));
5543
 
  cur_file= file_stack.data();
 
5530
  memset(file_stack, 0, sizeof(file_stack));
 
5531
  file_stack_end=
 
5532
    file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
 
5533
  cur_file= file_stack;
5544
5534
 
5545
5535
  /* Init block stack */
5546
5536
  memset(block_stack, 0, sizeof(block_stack));
5579
5569
      tmp= buff;
5580
5570
    }
5581
5571
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5582
 
    assert(cur_file == file_stack.data() && cur_file->file == 0);
 
5572
    assert(cur_file == file_stack && cur_file->file == 0);
5583
5573
    if (!(cur_file->file= fopen(buff, "r")))
5584
5574
    {
5585
5575
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5684
5674
  }
5685
5675
 
5686
5676
  server_initialized= 1;
5687
 
  if (cur_file == file_stack.data() && cur_file->file == 0)
 
5677
  if (cur_file == file_stack && cur_file->file == 0)
5688
5678
  {
5689
5679
    cur_file->file= stdin;
5690
5680
    cur_file->file_name= strdup("<stdin>");
5704
5694
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5705
5695
               opt_db, opt_port);
5706
5696
 
5707
 
  fill_global_error_names();
5708
 
 
5709
5697
  /* Use all time until exit if no explicit 'start_timer' */
5710
5698
  timer_start= timer_now();
5711
5699
 
6109
6097
  the time between executing the two commands.
6110
6098
*/
6111
6099
 
6112
 
void timer_output()
 
6100
void timer_output(void)
6113
6101
{
6114
6102
  if (timer_file)
6115
6103
  {
6123
6111
}
6124
6112
 
6125
6113
 
6126
 
uint64_t timer_now()
 
6114
uint64_t timer_now(void)
6127
6115
{
6128
6116
#if defined(HAVE_GETHRTIME)
6129
6117
  return gethrtime()/1000/1000;
6163
6151
  start= buff= (char *)malloc(strlen(from)+1);
6164
6152
  while (*from)
6165
6153
  {
 
6154
    char *to;
6166
6155
    uint32_t column_number;
6167
6156
 
6168
 
    char *to= get_string(&buff, &from, command);
 
6157
    to= get_string(&buff, &from, command);
6169
6158
    if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
6170
6159
      die("Wrong column number to replace_column in '%s'", command->query);
6171
6160
    if (!*from)
6184
6173
 
6185
6174
void free_replace_column()
6186
6175
{
6187
 
  for (uint32_t i= 0 ; i < max_replace_column; i++)
 
6176
  uint32_t i;
 
6177
  for (i=0 ; i < max_replace_column ; i++)
6188
6178
  {
6189
 
    free(replace_column[i]);
6190
 
    replace_column[i]= 0;
 
6179
    if (replace_column[i])
 
6180
    {
 
6181
      free(replace_column[i]);
 
6182
      replace_column[i]= 0;
 
6183
    }
6191
6184
  }
6192
6185
  max_replace_column= 0;
6193
6186
}
6208
6201
} POINTER_ARRAY;
6209
6202
 
6210
6203
struct st_replace;
6211
 
struct st_replace *init_replace(const char **from, const char **to, uint32_t count,
6212
 
                                char *word_end_chars);
 
6204
struct st_replace *init_replace(char * *from, char * *to, uint32_t count,
 
6205
                                char * word_end_chars);
6213
6206
int insert_pointer_name(POINTER_ARRAY *pa,char * name);
6214
6207
void replace_strings_append(struct st_replace *rep, string* ds,
6215
6208
                            const char *from, int len);
 
6209
void free_pointer_array(POINTER_ARRAY *pa);
6216
6210
 
6217
 
st_replace *glob_replace= NULL;
6218
 
// boost::scoped_ptr<st_replace> glob_replace;
 
6211
struct st_replace *glob_replace= NULL;
6219
6212
 
6220
6213
/*
6221
6214
  Get arguments for replace. The syntax is:
6225
6218
  variable is replaced.
6226
6219
*/
6227
6220
 
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
6221
void do_get_replace(struct st_command *command)
6239
6222
{
6240
6223
  uint32_t i;
6266
6249
    if (my_isspace(charset_info,i))
6267
6250
      *pos++= i;
6268
6251
  *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,
 
6252
  if (!(glob_replace= init_replace((char**) from_array.typelib.type_names,
 
6253
                                   (char**) to_array.typelib.type_names,
 
6254
                                   (uint32_t) from_array.typelib.count,
6272
6255
                                   word_end_chars)))
6273
6256
    die("Can't initialize replace from '%s'", command->query);
6274
6257
  free_pointer_array(&from_array);
6281
6264
 
6282
6265
void free_replace()
6283
6266
{
6284
 
  free(glob_replace);
6285
 
  glob_replace=0;
 
6267
 
 
6268
  if (glob_replace)
 
6269
  {
 
6270
    free(glob_replace);
 
6271
    glob_replace=0;
 
6272
  }
 
6273
  return;
6286
6274
}
6287
6275
 
6288
6276
 
6302
6290
void replace_strings_append(REPLACE *rep, string* ds,
6303
6291
                            const char *str, int len)
6304
6292
{
6305
 
  REPLACE *rep_pos;
6306
 
  REPLACE_STRING *rep_str;
 
6293
  register REPLACE *rep_pos;
 
6294
  register REPLACE_STRING *rep_str;
6307
6295
  const char *start, *from;
6308
6296
 
6309
6297
 
6356
6344
                 i.e. repeat the matching until the end of the string */
6357
6345
};
6358
6346
 
6359
 
class st_replace_regex
 
6347
struct st_replace_regex
6360
6348
{
6361
 
public:
6362
 
  st_replace_regex(char* expr);
6363
 
  int multi_reg_replace(char* val);
 
6349
  DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
6364
6350
 
6365
6351
  /*
6366
6352
    Temporary storage areas for substitutions. To reduce unnessary copying
6369
6355
    st_regex substition. At the end of substitutions  buf points to the
6370
6356
    one containing the final result.
6371
6357
  */
6372
 
  typedef vector<st_regex> regex_arr_t;
6373
 
 
6374
 
  char* buf_;
 
6358
  char* buf;
6375
6359
  char* even_buf;
6376
6360
  char* odd_buf;
6377
6361
  int even_buf_len;
6378
6362
  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
6363
};
6383
6364
 
6384
 
boost::scoped_ptr<st_replace_regex> glob_replace_regex;
 
6365
struct st_replace_regex *glob_replace_regex= 0;
6385
6366
 
6386
6367
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6387
6368
                char *string, int icase, int global);
6423
6404
  Returns: st_replace_regex struct with pairs of substitutions
6424
6405
*/
6425
6406
 
6426
 
st_replace_regex::st_replace_regex(char* expr)
 
6407
static struct st_replace_regex* init_replace_regex(char* expr)
6427
6408
{
 
6409
  struct st_replace_regex* res;
 
6410
  char* buf,*expr_end;
 
6411
  char* p;
 
6412
  char* buf_p;
6428
6413
  uint32_t expr_len= strlen(expr);
6429
6414
  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;
 
6415
  struct st_regex reg;
 
6416
 
 
6417
  res=(st_replace_regex*)malloc(sizeof(*res)+expr_len);
 
6418
  if (!res)
 
6419
    return NULL;
 
6420
  my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
 
6421
 
 
6422
  buf= (char*)res + sizeof(*res);
 
6423
  expr_end= expr + expr_len;
 
6424
  p= expr;
 
6425
  buf_p= buf;
6436
6426
 
6437
6427
  /* for each regexp substitution statement */
6438
6428
  while (p < expr_end)
6448
6438
 
6449
6439
    if (p == expr_end || ++p == expr_end)
6450
6440
    {
6451
 
      if (!regex_arr.empty())
 
6441
      if (res->regex_arr.elements)
6452
6442
        break;
6453
6443
      else
6454
6444
        goto err;
6487
6477
      p++;
6488
6478
      reg.global= 1;
6489
6479
    }
6490
 
    regex_arr.push_back(reg);
 
6480
 
 
6481
    /* done parsing the statement, now place it in regex_arr */
 
6482
    if (insert_dynamic(&res->regex_arr,(unsigned char*) &reg))
 
6483
      die("Out of memory");
6491
6484
  }
6492
 
  odd_buf_len= even_buf_len= buf0_.size();
6493
 
  even_buf= buf0_.data();
6494
 
  odd_buf= buf1_.data();
6495
 
  buf_= even_buf;
 
6485
  res->odd_buf_len= res->even_buf_len= 8192;
 
6486
  res->even_buf= (char*)malloc(res->even_buf_len);
 
6487
  res->odd_buf= (char*)malloc(res->odd_buf_len);
 
6488
  res->buf= res->even_buf;
6496
6489
 
6497
 
  return;
 
6490
  return res;
6498
6491
 
6499
6492
err:
 
6493
  free(res);
6500
6494
  die("Error parsing replace_regex \"%s\"", expr);
 
6495
  return 0;
6501
6496
}
6502
6497
 
6503
6498
/*
6519
6514
  in one pass
6520
6515
*/
6521
6516
 
6522
 
int st_replace_regex::multi_reg_replace(char* val)
 
6517
static int multi_reg_replace(struct st_replace_regex* r,char* val)
6523
6518
{
6524
 
  char* in_buf= val;
6525
 
  char* out_buf= even_buf;
6526
 
  int* buf_len_p= &even_buf_len;
6527
 
  buf_= 0;
 
6519
  uint32_t i;
 
6520
  char* in_buf, *out_buf;
 
6521
  int* buf_len_p;
 
6522
 
 
6523
  in_buf= val;
 
6524
  out_buf= r->even_buf;
 
6525
  buf_len_p= &r->even_buf_len;
 
6526
  r->buf= 0;
6528
6527
 
6529
6528
  /* For each substitution, do the replace */
6530
 
  BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
 
6529
  for (i= 0; i < r->regex_arr.elements; i++)
6531
6530
  {
 
6531
    struct st_regex re;
6532
6532
    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))
 
6533
 
 
6534
    get_dynamic(&r->regex_arr,(unsigned char*)&re,i);
 
6535
 
 
6536
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
 
6537
                     in_buf, re.icase, re.global))
6535
6538
    {
6536
6539
      /* if the buffer has been reallocated, make adjustements */
6537
6540
      if (save_out_buf != out_buf)
6538
6541
      {
6539
 
        if (save_out_buf == even_buf)
6540
 
          even_buf= out_buf;
 
6542
        if (save_out_buf == r->even_buf)
 
6543
          r->even_buf= out_buf;
6541
6544
        else
6542
 
          odd_buf= out_buf;
 
6545
          r->odd_buf= out_buf;
6543
6546
      }
6544
 
      buf_= out_buf;
 
6547
 
 
6548
      r->buf= out_buf;
6545
6549
      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;
 
6550
        in_buf= r->odd_buf;
 
6551
 
 
6552
      std::swap(in_buf,out_buf);
 
6553
 
 
6554
      buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
 
6555
        &r->odd_buf_len;
6549
6556
    }
6550
6557
  }
6551
 
  return buf_ == 0;
 
6558
 
 
6559
  return (r->buf == 0);
6552
6560
}
6553
6561
 
6554
6562
/*
6563
6571
void do_get_replace_regex(struct st_command *command)
6564
6572
{
6565
6573
  char *expr= command->first_argument;
6566
 
  glob_replace_regex.reset(new st_replace_regex(expr));
 
6574
  free_replace_regex();
 
6575
  if (!(glob_replace_regex=init_replace_regex(expr)))
 
6576
    die("Could not init replace_regex");
6567
6577
  command->last_argument= command->end;
6568
6578
}
6569
6579
 
 
6580
void free_replace_regex()
 
6581
{
 
6582
  if (glob_replace_regex)
 
6583
  {
 
6584
    delete_dynamic(&glob_replace_regex->regex_arr);
 
6585
    free(glob_replace_regex->even_buf);
 
6586
    free(glob_replace_regex->odd_buf);
 
6587
    free(glob_replace_regex);
 
6588
    glob_replace_regex=0;
 
6589
  }
 
6590
}
 
6591
 
 
6592
 
 
6593
 
6570
6594
/*
6571
6595
  Performs a regex substitution
6572
6596
 
6673
6697
#define SET_MALLOC_HUNC 64
6674
6698
#define LAST_CHAR_CODE 259
6675
6699
 
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
 
 
 
6700
typedef struct st_rep_set {
6686
6701
  uint32_t  *bits;        /* Pointer to used sets */
6687
6702
  short next[LAST_CHAR_CODE];    /* Pointer to next sets */
6688
6703
  uint32_t  found_len;      /* Best match to date */
6689
6704
  int  found_offset;
6690
6705
  uint32_t  table_offset;
6691
6706
  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
 
 
 
6707
} REP_SET;
 
6708
 
 
6709
typedef struct st_rep_sets {
6702
6710
  uint32_t    count;      /* Number of sets */
6703
6711
  uint32_t    extra;      /* Extra sets in buffer */
6704
 
  uint32_t    invisible;    /* Sets not shown */
 
6712
  uint32_t    invisible;    /* Sets not chown */
6705
6713
  uint32_t    size_of_bits;
6706
6714
  REP_SET  *set,*set_buffer;
6707
6715
  uint32_t    *bit_buffer;
6708
 
};
 
6716
} REP_SETS;
6709
6717
 
6710
 
struct FOUND_SET 
6711
 
{
 
6718
typedef struct st_found_set {
6712
6719
  uint32_t table_offset;
6713
6720
  int found_offset;
6714
 
};
 
6721
} FOUND_SET;
6715
6722
 
6716
 
struct FOLLOWS
6717
 
{
 
6723
typedef struct st_follow {
6718
6724
  int chr;
6719
6725
  uint32_t table_offset;
6720
6726
  uint32_t len;
6721
 
};
6722
 
 
6723
 
int init_sets(REP_SETS *sets, uint32_t states);
 
6727
} FOLLOWS;
 
6728
 
 
6729
 
 
6730
int init_sets(REP_SETS *sets,uint32_t states);
6724
6731
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)
 
6732
void make_sets_invisible(REP_SETS *sets);
 
6733
void free_last_set(REP_SETS *sets);
 
6734
void free_sets(REP_SETS *sets);
 
6735
void internal_set_bit(REP_SET *set, uint32_t bit);
 
6736
void internal_clear_bit(REP_SET *set, uint32_t bit);
 
6737
void or_bits(REP_SET *to,REP_SET *from);
 
6738
void copy_bits(REP_SET *to,REP_SET *from);
 
6739
int cmp_bits(REP_SET *set1,REP_SET *set2);
 
6740
int get_next_bit(REP_SET *set,uint32_t lastpos);
 
6741
int find_set(REP_SETS *sets,REP_SET *find);
 
6742
int find_found(FOUND_SET *found_set,uint32_t table_offset,
 
6743
               int found_offset);
 
6744
uint32_t start_at_word(char * pos);
 
6745
uint32_t end_of_word(char * pos);
 
6746
 
 
6747
static uint32_t found_sets=0;
 
6748
 
 
6749
 
 
6750
static uint32_t replace_len(char * str)
6730
6751
{
6731
6752
  uint32_t len=0;
6732
6753
  while (*str)
6739
6760
  return len;
6740
6761
}
6741
6762
 
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
6763
/* Init a replace structure for further calls */
6756
6764
 
6757
 
REPLACE *init_replace(const char **from, const char **to, uint32_t count, char *word_end_chars)
 
6765
REPLACE *init_replace(char * *from, char * *to,uint32_t count,
 
6766
                      char * word_end_chars)
6758
6767
{
6759
 
  const int SPACE_CHAR= 256;
6760
 
  const int START_OF_LINE= 257;
6761
 
  const int END_OF_LINE= 258;
 
6768
  static const int SPACE_CHAR= 256;
 
6769
  static const int START_OF_LINE= 257;
 
6770
  static const int END_OF_LINE= 258;
6762
6771
 
6763
6772
  uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6764
6773
  int used_sets,chr,default_state;
6765
6774
  char used_chars[LAST_CHAR_CODE],is_word_end[256];
6766
 
  char *to_pos, **to_array;
 
6775
  char * pos, *to_pos, **to_array;
 
6776
  REP_SETS sets;
 
6777
  REP_SET *set,*start_states,*word_states,*new_set;
 
6778
  FOLLOWS *follow,*follow_ptr;
 
6779
  REPLACE *replace;
 
6780
  FOUND_SET *found_set;
 
6781
  REPLACE_STRING *rep_str;
 
6782
 
6767
6783
 
6768
6784
  /* Count number of states */
6769
6785
  for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
6783
6799
  for (i=0 ; word_end_chars[i] ; i++)
6784
6800
    is_word_end[(unsigned char) word_end_chars[i]]=1;
6785
6801
 
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;
 
6802
  if (init_sets(&sets,states))
 
6803
    return(0);
6791
6804
  found_sets=0;
6792
 
  vector<FOUND_SET> found_set(max_length * count);
 
6805
  if (!(found_set= (FOUND_SET*) malloc(sizeof(FOUND_SET)*max_length*count)))
 
6806
                                
 
6807
  {
 
6808
    free_sets(&sets);
 
6809
    return(0);
 
6810
  }
6793
6811
  make_new_set(&sets);      /* Set starting set */
6794
 
  sets.make_sets_invisible();      /* Hide previus sets */
 
6812
  make_sets_invisible(&sets);      /* Hide previus sets */
6795
6813
  used_sets=-1;
6796
6814
  word_states=make_new_set(&sets);    /* Start of new word */
6797
6815
  start_states=make_new_set(&sets);    /* This is first state */
6798
 
  vector<FOLLOWS> follow(states + 2);
6799
 
  FOLLOWS *follow_ptr= &follow[1];
 
6816
  if (!(follow=(FOLLOWS*) malloc((states+2)*sizeof(FOLLOWS))))
 
6817
  {
 
6818
    free_sets(&sets);
 
6819
    free(found_set);
 
6820
    return(0);
 
6821
  }
 
6822
 
6800
6823
  /* Init follow_ptr[] */
6801
 
  for (i=0, states=1; i < count; i++)
 
6824
  for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
6802
6825
  {
6803
6826
    if (from[i][0] == '\\' && from[i][1] == '^')
6804
6827
    {
6805
 
      start_states->internal_set_bit(states + 1);
 
6828
      internal_set_bit(start_states,states+1);
6806
6829
      if (!from[i][2])
6807
6830
      {
6808
6831
        start_states->table_offset=i;
6811
6834
    }
6812
6835
    else if (from[i][0] == '\\' && from[i][1] == '$')
6813
6836
    {
6814
 
      start_states->internal_set_bit(states);
6815
 
      word_states->internal_set_bit(states);
 
6837
      internal_set_bit(start_states,states);
 
6838
      internal_set_bit(word_states,states);
6816
6839
      if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6817
6840
      {
6818
6841
        start_states->table_offset=i;
6821
6844
    }
6822
6845
    else
6823
6846
    {
6824
 
      word_states->internal_set_bit(states);
 
6847
      internal_set_bit(word_states,states);
6825
6848
      if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
6826
 
        start_states->internal_set_bit(states + 1);
 
6849
        internal_set_bit(start_states,states+1);
6827
6850
      else
6828
 
        start_states->internal_set_bit(states);
 
6851
        internal_set_bit(start_states,states);
6829
6852
    }
6830
 
    const char *pos;
6831
 
    for (pos= from[i], len=0; *pos ; pos++)
 
6853
    for (pos=from[i], len=0; *pos ; pos++)
6832
6854
    {
6833
6855
      if (*pos == '\\' && *(pos+1))
6834
6856
      {
6871
6893
  }
6872
6894
 
6873
6895
 
6874
 
  for (set_nr=0; set_nr < sets.count ; set_nr++)
 
6896
  for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6875
6897
  {
6876
6898
    set=sets.set+set_nr;
6877
6899
    default_state= 0;        /* Start from beginning */
6878
6900
 
6879
6901
    /* If end of found-string not found or start-set with current set */
6880
6902
 
6881
 
    for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
 
6903
    for (i= UINT32_MAX; (i=get_next_bit(set,i)) ;)
6882
6904
    {
6883
 
      if (!follow[i].chr && !default_state)
6884
 
        default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
 
6905
      if (!follow[i].chr)
 
6906
      {
 
6907
        if (! default_state)
 
6908
          default_state= find_found(found_set,set->table_offset,
 
6909
                                    set->found_offset+1);
 
6910
      }
6885
6911
    }
6886
 
    sets.set[used_sets].copy_bits(set);    /* Save set for changes */
 
6912
    copy_bits(sets.set+used_sets,set);    /* Save set for changes */
6887
6913
    if (!default_state)
6888
 
      sets.set[used_sets].or_bits(sets.set);  /* Can restart from start */
 
6914
      or_bits(sets.set+used_sets,sets.set);  /* Can restart from start */
6889
6915
 
6890
6916
    /* Find all chars that follows current sets */
6891
6917
    memset(used_chars, 0, sizeof(used_chars));
6892
 
    for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i)) ;)
 
6918
    for (i= UINT32_MAX; (i=get_next_bit(sets.set+used_sets,i)) ;)
6893
6919
    {
6894
6920
      used_chars[follow[i].chr]=1;
6895
6921
      if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6899
6925
 
6900
6926
    /* Mark word_chars used if \b is in state */
6901
6927
    if (used_chars[SPACE_CHAR])
6902
 
      for (const char *pos= word_end_chars ; *pos ; pos++)
 
6928
      for (pos= word_end_chars ; *pos ; pos++)
6903
6929
        used_chars[(int) (unsigned char) *pos] = 1;
6904
6930
 
6905
6931
    /* Handle other used characters */
6916
6942
        new_set->found_offset=set->found_offset+1;
6917
6943
        found_end=0;
6918
6944
 
6919
 
        for (i= UINT32_MAX ; (i= sets.set[used_sets].get_next_bit(i)) ; )
 
6945
        for (i= UINT32_MAX ; (i=get_next_bit(sets.set+used_sets,i)) ; )
6920
6946
        {
6921
6947
          if (!follow[i].chr || follow[i].chr == chr ||
6922
6948
              (follow[i].chr == SPACE_CHAR &&
6928
6954
                follow[i].len > found_end)
6929
6955
              found_end=follow[i].len;
6930
6956
            if (chr && follow[i].chr)
6931
 
              new_set->internal_set_bit(i + 1);    /* To next set */
 
6957
              internal_set_bit(new_set,i+1);    /* To next set */
6932
6958
            else
6933
 
              new_set->internal_set_bit(i);
 
6959
              internal_set_bit(new_set,i);
6934
6960
          }
6935
6961
        }
6936
6962
        if (found_end)
6937
6963
        {
6938
6964
          new_set->found_len=0;      /* Set for testing if first */
6939
6965
          bits_set=0;
6940
 
          for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
 
6966
          for (i= UINT32_MAX; (i=get_next_bit(new_set,i)) ;)
6941
6967
          {
6942
6968
            if ((follow[i].chr == SPACE_CHAR ||
6943
6969
                 follow[i].chr == END_OF_LINE) && ! chr)
6947
6973
            if (follow[bit_nr-1].len < found_end ||
6948
6974
                (new_set->found_len &&
6949
6975
                 (chr == 0 || !follow[bit_nr].chr)))
6950
 
              new_set->internal_clear_bit(i);
 
6976
              internal_clear_bit(new_set,i);
6951
6977
            else
6952
6978
            {
6953
6979
              if (chr == 0 || !follow[bit_nr].chr)
6963
6989
          }
6964
6990
          if (bits_set == 1)
6965
6991
          {
6966
 
            set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6967
 
            sets.free_last_set();
 
6992
            set->next[chr] = find_found(found_set,
 
6993
                                        new_set->table_offset,
 
6994
                                        new_set->found_offset);
 
6995
            free_last_set(&sets);
6968
6996
          }
6969
6997
          else
6970
 
            set->next[chr] = sets.find_set(new_set);
 
6998
            set->next[chr] = find_set(&sets,new_set);
6971
6999
        }
6972
7000
        else
6973
 
          set->next[chr] = sets.find_set(new_set);
 
7001
          set->next[chr] = find_set(&sets,new_set);
6974
7002
      }
6975
7003
    }
6976
7004
  }
6977
7005
 
6978
7006
  /* Alloc replace structure for the replace-state-machine */
6979
7007
 
6980
 
  REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
 
    + sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
6982
 
  if (replace)
 
7008
  if ((replace=(REPLACE*) malloc(sizeof(REPLACE)*(sets.count)+
 
7009
                                 sizeof(REPLACE_STRING)*(found_sets+1)+
 
7010
                                 sizeof(char *)*count+result_len)))
6983
7011
  {
6984
7012
    memset(replace, 0, sizeof(REPLACE)*(sets.count)+
6985
7013
                       sizeof(REPLACE_STRING)*(found_sets+1)+
6996
7024
    rep_str[0].replace_string=0;
6997
7025
    for (i=1 ; i <= found_sets ; i++)
6998
7026
    {
6999
 
      const char *pos= from[found_set[i-1].table_offset];
 
7027
      pos=from[found_set[i-1].table_offset];
7000
7028
      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);
 
7029
      rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
 
7030
      rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
 
7031
      rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
 
7032
        end_of_word(pos);
7004
7033
    }
7005
7034
    for (i=0 ; i < sets.count ; i++)
7006
7035
    {
7011
7040
          replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7012
7041
    }
7013
7042
  }
7014
 
  sets.free_sets();
7015
 
  return replace;
 
7043
  free(follow);
 
7044
  free_sets(&sets);
 
7045
  free(found_set);
 
7046
  return(replace);
7016
7047
}
7017
7048
 
7018
7049
 
7033
7064
 
7034
7065
/* Make help sets invisible for nicer codeing */
7035
7066
 
7036
 
void REP_SETS::make_sets_invisible()
 
7067
void make_sets_invisible(REP_SETS *sets)
7037
7068
{
7038
 
  invisible= count;
7039
 
  set += count;
7040
 
  count= 0;
 
7069
  sets->invisible=sets->count;
 
7070
  sets->set+=sets->count;
 
7071
  sets->count=0;
7041
7072
}
7042
7073
 
7043
7074
REP_SET *make_new_set(REP_SETS *sets)
7075
7106
  return make_new_set(sets);
7076
7107
}
7077
7108
 
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
 
}
 
7109
void free_last_set(REP_SETS *sets)
 
7110
{
 
7111
  sets->count--;
 
7112
  sets->extra++;
 
7113
  return;
 
7114
}
 
7115
 
 
7116
void free_sets(REP_SETS *sets)
 
7117
{
 
7118
  free(sets->set_buffer);
 
7119
  free(sets->bit_buffer);
 
7120
  return;
 
7121
}
 
7122
 
 
7123
void internal_set_bit(REP_SET *set, uint32_t bit)
 
7124
{
 
7125
  set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
 
7126
  return;
 
7127
}
 
7128
 
 
7129
void internal_clear_bit(REP_SET *set, uint32_t bit)
 
7130
{
 
7131
  set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
 
7132
  return;
 
7133
}
 
7134
 
 
7135
 
 
7136
void or_bits(REP_SET *to,REP_SET *from)
 
7137
{
 
7138
  register uint32_t i;
 
7139
  for (i=0 ; i < to->size_of_bits ; i++)
 
7140
    to->bits[i]|=from->bits[i];
 
7141
  return;
 
7142
}
 
7143
 
 
7144
void copy_bits(REP_SET *to,REP_SET *from)
 
7145
{
 
7146
  memcpy(to->bits,from->bits,
 
7147
         (size_t) (sizeof(uint32_t) * to->size_of_bits));
 
7148
}
 
7149
 
 
7150
int cmp_bits(REP_SET *set1,REP_SET *set2)
 
7151
{
 
7152
  return memcmp(set1->bits,set2->bits, sizeof(uint32_t) * set1->size_of_bits);
 
7153
}
 
7154
 
7116
7155
 
7117
7156
/* Get next set bit from set. */
7118
7157
 
7119
 
int REP_SET::get_next_bit(uint32_t lastpos) const
 
7158
int get_next_bit(REP_SET *set,uint32_t lastpos)
7120
7159
{
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)
 
7160
  uint32_t pos,*start,*end,bits;
 
7161
 
 
7162
  start=set->bits+ ((lastpos+1) / WORD_BIT);
 
7163
  end=set->bits + set->size_of_bits;
 
7164
  bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
 
7165
 
 
7166
  while (! bits && ++start < end)
 
7167
    bits=start[0];
 
7168
  if (!bits)
7128
7169
    return 0;
7129
 
  uint32_t pos= (start - bits) * WORD_BIT;
7130
 
  while (!(bits0 & 1))
 
7170
  pos=(uint32_t) (start-set->bits)*WORD_BIT;
 
7171
  while (! (bits & 1))
7131
7172
  {
7132
 
    bits0 >>=1;
 
7173
    bits>>=1;
7133
7174
    pos++;
7134
7175
  }
7135
7176
  return pos;
7139
7180
   free given set, else put in given set in sets and return its
7140
7181
   position */
7141
7182
 
7142
 
int REP_SETS::find_set(const REP_SET *find)
 
7183
int find_set(REP_SETS *sets,REP_SET *find)
7143
7184
{
7144
 
  uint32_t i= 0;
7145
 
  for (; i < count - 1; i++)
 
7185
  uint32_t i;
 
7186
  for (i=0 ; i < sets->count-1 ; i++)
7146
7187
  {
7147
 
    if (!set[i].cmp_bits(find))
 
7188
    if (!cmp_bits(sets->set+i,find))
7148
7189
    {
7149
 
      free_last_set();
 
7190
      free_last_set(sets);
7150
7191
      return i;
7151
7192
    }
7152
7193
  }
7160
7201
   set->next[] == -1 is reserved for end without replaces.
7161
7202
*/
7162
7203
 
7163
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
 
7204
int find_found(FOUND_SET *found_set,uint32_t table_offset, int found_offset)
7164
7205
{
7165
 
  uint32_t i= 0;
7166
 
  for (; i < found_sets; i++)
7167
 
  {
 
7206
  int i;
 
7207
  for (i=0 ; (uint32_t) i < found_sets ; i++)
7168
7208
    if (found_set[i].table_offset == table_offset &&
7169
7209
        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;
 
7210
      return -i-2;
 
7211
  found_set[i].table_offset=table_offset;
 
7212
  found_set[i].found_offset=found_offset;
7174
7213
  found_sets++;
7175
 
  return - i - 2; // return new postion
 
7214
  return -i-2;        /* return new postion */
 
7215
}
 
7216
 
 
7217
/* Return 1 if regexp starts with \b or ends with \b*/
 
7218
 
 
7219
uint32_t start_at_word(char * pos)
 
7220
{
 
7221
  return (((!memcmp(pos, "\\b",2) && pos[2]) ||
 
7222
           !memcmp(pos, "\\^", 2)) ? 1 : 0);
 
7223
}
 
7224
 
 
7225
uint32_t end_of_word(char * pos)
 
7226
{
 
7227
  char * end= strchr(pos, '\0');
 
7228
  return ((end > pos+2 && !memcmp(end-2, "\\b", 2)) ||
 
7229
          (end >= pos+2 && !memcmp(end-2, "\\$",2))) ? 1 : 0;
7176
7230
}
7177
7231
 
7178
7232
/****************************************************************************
7251
7305
} /* insert_pointer_name */
7252
7306
 
7253
7307
 
 
7308
/* free pointer array */
 
7309
 
 
7310
void free_pointer_array(POINTER_ARRAY *pa)
 
7311
{
 
7312
  if (pa->typelib.count)
 
7313
  {
 
7314
    pa->typelib.count=0;
 
7315
    free((char*) pa->typelib.type_names);
 
7316
    pa->typelib.type_names=0;
 
7317
    free(pa->str);
 
7318
  }
 
7319
} /* free_pointer_array */
 
7320
 
 
7321
 
7254
7322
/* Functions that uses replace and replace_regex */
7255
7323
 
7256
7324
/* Append the string to ds, with optional replace */
7257
 
void replace_append_mem(string *ds, const char *val, int len)
 
7325
void replace_append_mem(string *ds,
 
7326
                        const char *val, int len)
7258
7327
{
7259
7328
  char *v= strdup(val);
7260
7329
 
7261
 
  if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
 
7330
  if (glob_replace_regex)
7262
7331
  {
7263
 
    v= glob_replace_regex->buf_;
7264
 
    len= strlen(v);
 
7332
    /* Regex replace */
 
7333
    if (!multi_reg_replace(glob_replace_regex, v))
 
7334
    {
 
7335
      v= glob_replace_regex->buf;
 
7336
      len= strlen(v);
 
7337
    }
7265
7338
  }
 
7339
 
7266
7340
  if (glob_replace)
7267
7341
  {
7268
7342
    /* Normal replace */
7269
7343
    replace_strings_append(glob_replace, ds, v, len);
7270
7344
  }
7271
7345
  else
 
7346
  {
7272
7347
    ds->append(v, len);
 
7348
  }
7273
7349
}
7274
7350
 
7275
7351
 
7338
7414
 
7339
7415
  return;
7340
7416
}
7341
 
 
7342
 
static void free_all_replace()
7343
 
{
7344
 
  free_replace();
7345
 
  glob_replace_regex.reset();
7346
 
  free_replace_column();
7347
 
}