50
50
#ifdef HAVE_SYS_WAIT_H
51
51
#include <sys/wait.h>
55
#include <sys/types.h>
54
58
#include PCRE_HEADER
56
#include <mysys/hash.h>
57
60
#include <stdarg.h>
59
62
#include "errname.h"
61
64
/* Added this for string translation. */
62
#include <drizzled/gettext.h>
65
#include "drizzled/gettext.h"
66
#include "drizzled/hash.h"
67
#include "drizzled/drizzle_time.h"
68
#include "drizzled/charset.h"
64
70
#ifndef DRIZZLE_RETURN_SERVER_GONE
65
71
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
68
74
using namespace std;
75
using namespace drizzled;
72
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
73
bool get_one_option(int optid, const struct my_option *, char *argument);
78
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
80
int get_one_option(int optid, const struct option *, char *argument);
76
82
#define MAX_VAR_NAME_LENGTH 256
77
83
#define MAX_COLUMNS 256
78
#define MAX_EMBEDDED_SERVER_ARGS 64
79
84
#define MAX_DELIMITER_LENGTH 16
80
85
/* Flags controlling send and reap */
81
86
#define QUERY_SEND_FLAG 1
98
103
const char *opt_testdir= NULL;
99
104
static uint32_t opt_port= 0;
100
105
static int opt_max_connect_retries;
101
static bool opt_compress= false, silent= false, verbose= false;
102
static bool debug_info_flag= false, debug_check_flag= false;
106
static bool silent= false, verbose= false;
103
107
static bool tty_password= false;
104
108
static bool opt_mark_progress= false;
105
109
static bool parsing_disabled= false;
111
115
static bool abort_on_error= true;
112
116
static bool server_initialized= false;
113
117
static bool is_windows= false;
118
static bool opt_mysql= false;
114
119
static char **default_argv;
115
120
static const char *load_default_groups[]= { "drizzletest", "client", 0 };
116
121
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
118
123
static uint32_t start_lineno= 0; /* Start line of current command */
119
static uint32_t my_end_arg= 0;
121
125
/* Number of lines of the result to include in failure report */
122
126
static uint32_t opt_tail_lines= 0;
386
388
char *query, *query_buf,*first_argument,*last_argument,*end;
387
389
int first_word_len, query_len;
388
390
bool abort_on_error;
389
struct st_expected_errors expected_errors;
390
char require_file[FN_REFLEN];
391
st_expected_errors expected_errors;
391
393
enum enum_commands type;
396
: query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
397
end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
398
require_file(""), type(Q_CONNECTION)
400
memset(&expected_errors, 0, sizeof(st_expected_errors));
405
if (query_buf != NULL)
394
412
TYPELIB command_typelib= {array_elements(command_names),"",
412
430
VAR* var_from_env(const char *, const char *);
413
431
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
415
extern "C" void var_free(void* v);
433
void var_free(pair<string, VAR*> v);
416
434
VAR* var_get(const char *var_name, const char** var_name_end,
417
435
bool raw, bool ignore_not_existing);
418
436
void eval_expr(VAR* v, const char *p, const char** p_end);
1130
1143
char buff[512];
1132
if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0)
1145
if ((fd= internal::my_open(filename, O_RDONLY, MYF(0))) < 0)
1133
1146
die("Failed to open file '%s'", filename);
1134
while((len= my_read(fd, (unsigned char*)&buff,
1147
while((len= internal::my_read(fd, (unsigned char*)&buff,
1135
1148
sizeof(buff), MYF(0))) > 0)
1137
1150
char *p= buff, *start= buff;
1332
static int compare_files2(File fd, const char* filename2)
1345
static int compare_files2(int fd, const char* filename2)
1334
1347
int error= RESULT_OK;
1336
1349
uint32_t len, len2;
1337
1350
char buff[512], buff2[512];
1338
1351
const char *fname= filename2;
1339
1352
string tmpfile;
1341
if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1354
if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1343
my_close(fd, MYF(0));
1356
internal::my_close(fd, MYF(0));
1344
1357
if (opt_testdir != NULL)
1346
1359
tmpfile= opt_testdir;
1349
1362
tmpfile.append(filename2);
1350
1363
fname= tmpfile.c_str();
1352
if ((fd2= my_open(fname, O_RDONLY, MYF(0))) < 0)
1365
if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1354
my_close(fd, MYF(0));
1367
internal::my_close(fd, MYF(0));
1356
1369
die("Failed to open second file: '%s'", fname);
1359
while((len= my_read(fd, (unsigned char*)&buff,
1372
while((len= internal::my_read(fd, (unsigned char*)&buff,
1360
1373
sizeof(buff), MYF(0))) > 0)
1362
if ((len2= my_read(fd2, (unsigned char*)&buff2,
1375
if ((len2= internal::my_read(fd2, (unsigned char*)&buff2,
1363
1376
sizeof(buff2), MYF(0))) < len)
1365
1378
/* File 2 was smaller */
1436
1449
static int string_cmp(string* ds, const char *fname)
1440
1453
char temp_file_path[FN_REFLEN];
1442
if ((fd= create_temp_file(temp_file_path, NULL,
1455
if ((fd= internal::create_temp_file(temp_file_path, NULL,
1443
1456
"tmp", MYF(MY_WME))) < 0)
1444
1457
die("Failed to create temporary file for ds");
1446
1459
/* Write ds to temporary file and set file pos to beginning*/
1447
if (my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
1460
if (internal::my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
1448
1461
MYF(MY_FNABP | MY_WME)) ||
1449
1462
lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
1451
my_close(fd, MYF(0));
1464
internal::my_close(fd, MYF(0));
1452
1465
/* Remove the temporary file */
1453
my_delete(temp_file_path, MYF(0));
1466
internal::my_delete(temp_file_path, MYF(0));
1454
1467
die("Failed to write file '%s'", temp_file_path);
1457
1470
error= compare_files2(fd, fname);
1459
my_close(fd, MYF(0));
1472
internal::my_close(fd, MYF(0));
1460
1473
/* Remove the temporary file */
1461
my_delete(temp_file_path, MYF(0));
1474
internal::my_delete(temp_file_path, MYF(0));
1501
1514
char reject_file[FN_REFLEN];
1502
1515
size_t reject_length;
1503
dirname_part(reject_file, result_file_name, &reject_length);
1516
internal::dirname_part(reject_file, result_file_name, &reject_length);
1505
1518
if (access(reject_file, W_OK) == 0)
1507
1520
/* Result file directory is writable, save reject file there */
1508
fn_format(reject_file, result_file_name, NULL,
1521
internal::fn_format(reject_file, result_file_name, NULL,
1509
1522
".reject", MY_REPLACE_EXT);
1513
1526
/* Put reject file in opt_logdir */
1514
fn_format(reject_file, result_file_name, opt_logdir,
1527
internal::fn_format(reject_file, result_file_name, opt_logdir,
1515
1528
".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1517
1530
str_to_file(reject_file, ds->c_str(), ds->length());
1548
static void check_require(string* ds, const char *fname)
1561
static void check_require(string* ds, const string &fname)
1552
if (string_cmp(ds, fname))
1565
if (string_cmp(ds, fname.c_str()))
1554
1567
char reason[FN_REFLEN];
1555
fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
1568
internal::fn_format(reason, fname.c_str(), "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
1556
1569
abort_not_supported_test("Test requires: '%s'", reason);
1696
1702
if (length >= MAX_VAR_NAME_LENGTH)
1697
1703
die("Too long variable name: %s", save_var_name);
1699
if (!(v = (VAR*) hash_search(&var_hash, (const unsigned char*) save_var_name,
1705
string save_var_name_str(save_var_name, length);
1706
drizzled::hash_map<string, VAR*>::iterator iter=
1707
var_hash.find(save_var_name_str);
1708
if (iter == var_hash.end())
1702
1710
char buff[MAX_VAR_NAME_LENGTH+1];
1703
1711
strncpy(buff, save_var_name, length);
1704
1712
buff[length]= '\0';
1705
1713
v= var_from_env(buff, "");
1707
1719
var_name--; /* Point at last character */
1729
1741
static VAR *var_obtain(const char *name, int len)
1732
if ((v = (VAR*)hash_search(&var_hash, (const unsigned char *) name, len)))
1734
v = var_init(0, name, len, "", 0);
1735
my_hash_insert(&var_hash, (unsigned char*)v);
1743
string var_name(name, len);
1744
drizzled::hash_map<string, VAR*>::iterator iter=
1745
var_hash.find(var_name);
1746
if (iter != var_hash.end())
1747
return (*iter).second;
1748
VAR *v = var_init(0, name, len, "", 0);
1749
var_hash.insert(make_pair(var_name, v));
2133
2146
char buff[FN_REFLEN];
2135
if (!test_if_hard_path(name))
2148
if (!internal::test_if_hard_path(name))
2137
sprintf(buff,"%s%s",opt_basedir,name);
2150
snprintf(buff, sizeof(buff), "%s%s",opt_basedir,name);
2140
fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2153
internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2142
2155
if (cur_file == file_stack_end)
2143
2156
die("Source directives are nesting too deep");
2979
2992
read_until_delimiter(&ds_script, &ds_delimiter);
2981
2994
/* Create temporary file name */
2982
if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
2995
if ((fd= internal::create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
2983
2996
"tmp", MYF(MY_WME))) < 0)
2984
2997
die("Failed to create temporary file for perl command");
2985
my_close(fd, MYF(0));
2998
internal::my_close(fd, MYF(0));
2987
3000
str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
3303
3316
die("Missing argument to %.*s", command->first_word_len, command->query);
3304
3317
sleep_start= p;
3305
/* Check that arg starts with a digit, not handled by my_strtod */
3318
/* Check that arg starts with a digit, not handled by internal::my_strtod */
3306
3319
if (!my_isdigit(charset_info, *sleep_start))
3307
3320
die("Invalid argument to %.*s \"%s\"", command->first_word_len,
3308
3321
command->query,command->first_argument);
4156
static int my_strnncoll_simple(const CHARSET_INFO * const cs, const unsigned char *s, size_t slen,
4157
const unsigned char *t, size_t tlen,
4160
size_t len = ( slen > tlen ) ? tlen : slen;
4161
unsigned char *map= cs->sort_order;
4162
if (t_is_prefix && slen > tlen)
4166
if (map[*s++] != map[*t++])
4167
return ((int) map[s[-1]] - (int) map[t[-1]]);
4170
We can't use (slen - tlen) here as the result may be outside of the
4171
precision of a signed int
4173
return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
4135
4176
static int read_line(char *buf, int size)
4137
4178
char c, last_quote= 0;
4548
4587
{"character-sets-dir", OPT_CHARSETS_DIR,
4549
4588
"Directory where character sets are.", (char**) &opt_charsets_dir,
4550
4589
(char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4551
{"compress", 'C', "Use the compressed server/client protocol.",
4552
(char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
4554
4590
{"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
4555
4591
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4556
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
4557
(char**) &debug_check_flag, (char**) &debug_check_flag, 0,
4558
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4559
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
4560
(char**) &debug_info_flag, (char**) &debug_info_flag,
4561
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4562
4592
{"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
4563
4593
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4564
4594
{"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
4576
4606
"Max number of connection attempts when connecting to server",
4577
4607
(char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
4578
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,
4579
4612
{"password", 'P', "Password to use when connecting to server.",
4580
4613
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
4581
4614
{"port", 'p', "Port number to use for connection or 0 for default to, in "
4589
4622
{"result-file", 'R', "Read/Store result from/in this file.",
4590
4623
(char**) &result_file_name, (char**) &result_file_name, 0,
4591
4624
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4592
{"server-arg", 'A', "Send option value to embedded server as a parameter.",
4593
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4594
{"server-file", 'F', "Read embedded server arguments from file.",
4595
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4596
4625
{"silent", 's', "Suppress all normal output. Synonym for --quiet.",
4597
4626
(char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4598
4627
{"sleep", 'T', "Sleep always this many seconds on sleep commands.",
4629
4658
print_version();
4630
4659
printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
4660
printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
4631
4661
printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
4632
4662
printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
4633
printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
4663
printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
4634
4664
my_print_help(my_long_options);
4635
4665
printf(" --no-defaults Don't read default options from any options file.\n");
4636
4666
my_print_variables(my_long_options);
4640
Read arguments for embedded server and put them into
4641
embedded_server_args[]
4644
static void read_embedded_server_arguments(const char *name)
4646
char argument[1024],buff[FN_REFLEN], *str=0;
4649
if (!test_if_hard_path(name))
4651
sprintf(buff,"%s%s",opt_basedir,name);
4654
fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
4656
if (!embedded_server_arg_count)
4658
embedded_server_arg_count=1;
4659
embedded_server_args[0]= (char*) ""; /* Progname */
4661
if (!(file= fopen(buff, "r")))
4662
die("Failed to open file '%s'", buff);
4664
while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
4665
(str=fgets(argument,sizeof(argument), file)))
4667
*(strchr(str, '\0')-1)=0; /* Remove end newline */
4668
if (!(embedded_server_args[embedded_server_arg_count]=
4669
(char*) strdup(str)))
4672
die("Out of memory");
4675
embedded_server_arg_count++;
4679
die("Too many arguments in option file: %s",name);
4685
bool get_one_option(int optid, const struct my_option *, char *argument)
4669
int get_one_option(int optid, const struct option *, char *argument)
4687
4671
char *endchar= NULL;
4688
4672
uint64_t temp_drizzle_port= 0;
4696
4680
char buff[FN_REFLEN];
4697
if (!test_if_hard_path(argument))
4681
if (!internal::test_if_hard_path(argument))
4699
sprintf(buff,"%s%s",opt_basedir,argument);
4683
snprintf(buff, sizeof(buff), "%s%s",opt_basedir,argument);
4700
4684
argument= buff;
4702
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4686
internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4703
4687
assert(cur_file == file_stack && cur_file->file == 0);
4704
4688
if (!(cur_file->file= fopen(buff, "r")))
4705
die("Could not open '%s' for reading: errno = %d", buff, errno);
4690
fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
4691
return EXIT_ARGUMENT_INVALID;
4706
4693
if (!(cur_file->file_name= strdup(buff)))
4707
die("Out of memory");
4695
fprintf(stderr, _("Out of memory"));
4696
return EXIT_OUT_OF_MEMORY;
4708
4698
cur_file->lineno= 1;
4713
4703
static char buff[FN_REFLEN];
4714
if (!test_if_hard_path(argument))
4704
if (!internal::test_if_hard_path(argument))
4716
sprintf(buff,"%s%s",opt_basedir,argument);
4706
snprintf(buff, sizeof(buff), "%s%s",opt_basedir,argument);
4717
4707
argument= buff;
4719
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4709
internal::fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4720
4710
timer_file= buff;
4721
4711
unlink(timer_file); /* Ignore error, may not exist */
4832
4805
char buff[FN_REFLEN];
4833
4806
int flags= O_WRONLY | O_CREAT;
4834
if (!test_if_hard_path(fname))
4807
if (!internal::test_if_hard_path(fname))
4836
sprintf(buff,"%s%s",opt_basedir,fname);
4809
snprintf(buff, sizeof(buff), "%s%s",opt_basedir,fname);
4839
fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4812
internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4842
4815
flags|= O_TRUNC;
4843
if ((fd= my_open(buff, flags,
4816
if ((fd= internal::my_open(buff, flags,
4844
4817
MYF(MY_WME | MY_FFNF))) < 0)
4845
4818
die("Could not open '%s' for writing: errno = %d", buff, errno);
4846
4819
if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
4847
4820
die("Could not find end of file '%s': errno = %d", buff, errno);
4848
if (my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
4821
if (internal::my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
4849
4822
die("write failed");
4850
my_close(fd, MYF(0));
4823
internal::my_close(fd, MYF(0));
5626
5598
cur_block->ok= true; /* Outer block should always be executed */
5627
5599
cur_block->cmd= cmd_none;
5629
if (hash_init(&var_hash, charset_info,
5630
1024, 0, 0, get_var_key, var_free, MYF(0)))
5631
die("Variable hash initialization failed");
5633
5601
var_set_string("$DRIZZLE_SERVER_VERSION", drizzle_version());
5635
5603
memset(&master_pos, 0, sizeof(master_pos));
6545
6539
icase - flag, if set to 1 the match is case insensitive
6547
6541
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
6548
char *replace, char *in_string, int icase)
6542
char *replace, char *in_string, int icase, int global)
6550
string string_to_match(in_string);
6551
6544
const char *error= NULL;
6553
6546
int ovector[3];
6554
6547
pcre *re= pcre_compile(pattern,
6555
icase ? PCRE_CASELESS : 0,
6548
icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
6556
6549
&error, &erroffset, NULL);
6557
6550
if (re == NULL)
6560
int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6568
char *substring_to_replace= in_string + ovector[0];
6569
int substring_length= ovector[1] - ovector[0];
6570
*buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6571
char * new_buf = (char *)malloc(*buf_len_p+1);
6572
if (new_buf == NULL)
6578
memset(new_buf, 0, *buf_len_p+1);
6579
strncpy(new_buf, in_string, substring_to_replace-in_string);
6580
strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6581
strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6582
substring_to_replace + substring_length,
6585
- (substring_to_replace-in_string));
6556
int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6564
char *substring_to_replace= in_string + ovector[0];
6565
int substring_length= ovector[1] - ovector[0];
6566
*buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6567
char * new_buf = (char *)malloc(*buf_len_p+1);
6568
if (new_buf == NULL)
6574
memset(new_buf, 0, *buf_len_p+1);
6575
strncpy(new_buf, in_string, substring_to_replace-in_string);
6576
strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6577
strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6578
substring_to_replace + substring_length,
6581
- (substring_to_replace-in_string));
6589
/* Repeatedly replace the string with the matched regex */
6590
string subject(in_string);
6591
size_t replace_length= strlen(replace);
6592
size_t current_position= 0;
6594
while(0 >= (rc= pcre_exec(re, NULL, subject.c_str() + current_position, subject.length() - current_position,
6597
current_position= static_cast<size_t>(ovector[0]);
6598
replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6599
subject.replace(current_position, replace_length, replace, replace_length);
6602
char *new_buf = (char *) malloc(subject.length() + 1);
6603
if (new_buf == NULL)
6608
memset(new_buf, 0, subject.length() + 1);
6609
strncpy(new_buf, subject.c_str(), subject.length());
6610
*buf_len_p= subject.length() + 1;