40
34
#define MTEST_VERSION "3.3"
42
37
#include "client_priv.h"
38
#include <drizzle_version.h>
39
#include <mysqld_error.h>
52
45
#ifdef HAVE_SYS_WAIT_H
53
46
#include <sys/wait.h>
57
#include <sys/types.h>
59
#include <boost/array.hpp>
60
#include <boost/foreach.hpp>
61
#include <boost/program_options.hpp>
62
#include <boost/smart_ptr.hpp>
67
#include <boost/unordered_map.hpp>
69
/* 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>
76
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
78
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
81
namespace po= boost::program_options;
83
using namespace drizzled;
86
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
88
int get_one_option(int optid, const struct option *, char *argument);
90
51
#define MAX_VAR_NAME_LENGTH 256
91
52
#define MAX_COLUMNS 256
53
#define MAX_EMBEDDED_SERVER_ARGS 64
92
54
#define MAX_DELIMITER_LENGTH 16
93
56
/* Flags controlling send and reap */
94
57
#define QUERY_SEND_FLAG 1
95
58
#define QUERY_REAP_FLAG 2
97
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
98
ErrorCodes global_error_names;
61
OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION,
101
62
OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
102
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
63
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES
106
66
static int record= 0, opt_sleep= -1;
107
static char *opt_pass= NULL;
108
const char *unix_sock= NULL;
109
static uint32_t opt_port= 0;
110
static uint32_t opt_max_connect_retries;
111
static bool silent= false, verbose= false;
112
static bool opt_mark_progress= false;
113
static bool parsing_disabled= false;
114
static bool display_result_vertically= false,
115
display_metadata= false, display_result_sorted= false;
116
static bool disable_query_log= false, disable_result_log= false;
117
static bool disable_warnings= false;
118
static bool disable_info= true;
119
static bool abort_on_error= true;
120
static bool server_initialized= false;
121
static bool is_windows= false;
122
static bool use_drizzle_protocol= false;
67
static char *opt_db= 0, *opt_pass= 0;
68
const char *opt_user= 0, *opt_host= 0, *unix_sock= 0, *opt_basedir= "./";
69
const char *opt_logdir= "";
70
const char *opt_include= 0, *opt_charsets_dir;
71
static int opt_port= 0;
72
static int opt_max_connect_retries;
73
static bool opt_compress= 0, silent= 0, verbose= 0;
74
static bool debug_info_flag= 0, debug_check_flag= 0;
75
static bool tty_password= 0;
76
static bool opt_mark_progress= 0;
77
static bool parsing_disabled= 0;
78
static bool display_result_vertically= FALSE,
79
display_metadata= FALSE, display_result_sorted= FALSE;
80
static bool disable_query_log= 0, disable_result_log= 0;
81
static bool disable_warnings= 0;
82
static bool disable_info= 1;
83
static bool abort_on_error= 1;
84
static bool server_initialized= 0;
85
static bool is_windows= 0;
86
static char **default_argv;
87
static const char *load_default_groups[]= { "mysqltest", "client", 0 };
123
88
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
124
static void free_all_replace();
126
std::string opt_basedir,
139
static uint32_t start_lineno= 0; /* Start line of current command */
90
static uint start_lineno= 0; /* Start line of current command */
91
static uint my_end_arg= 0;
141
93
/* Number of lines of the result to include in failure report */
142
static uint32_t opt_tail_lines= 0;
94
static uint opt_tail_lines= 0;
144
96
static char delimiter[MAX_DELIMITER_LENGTH]= ";";
145
static uint32_t delimiter_length= 1;
97
static uint delimiter_length= 1;
147
99
static char TMPDIR[FN_REFLEN];
385
348
enum match_err_type type;
389
char sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE+1]; /* \0 terminated string */
352
char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */
393
356
struct st_expected_errors
395
358
struct st_match_err err[10];
399
static st_expected_errors saved_expected_errors;
361
static struct st_expected_errors saved_expected_errors;
404
365
char *query, *query_buf,*first_argument,*last_argument,*end;
405
366
int first_word_len, query_len;
406
367
bool abort_on_error;
407
st_expected_errors expected_errors;
412
: query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
413
end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
414
require_file(""), type(Q_CONNECTION)
416
memset(&expected_errors, 0, sizeof(st_expected_errors));
368
struct st_expected_errors expected_errors;
369
char require_file[FN_REFLEN];
370
enum enum_commands type;
425
373
TYPELIB command_typelib= {array_elements(command_names),"",
428
string ds_res, ds_progress, ds_warning_messages;
376
DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
430
378
char builtin_echo[FN_REFLEN];
432
380
void die(const char *fmt, ...)
433
__attribute__((format(printf, 1, 2)));
381
ATTRIBUTE_FORMAT(printf, 1, 2);
434
382
void abort_not_supported_test(const char *fmt, ...)
435
__attribute__((format(printf, 1, 2)));
383
ATTRIBUTE_FORMAT(printf, 1, 2);
436
384
void verbose_msg(const char *fmt, ...)
437
__attribute__((format(printf, 1, 2)));
385
ATTRIBUTE_FORMAT(printf, 1, 2);
438
386
void warning_msg(const char *fmt, ...)
439
__attribute__((format(printf, 1, 2)));
387
ATTRIBUTE_FORMAT(printf, 1, 2);
440
388
void log_msg(const char *fmt, ...)
441
__attribute__((format(printf, 1, 2)));
389
ATTRIBUTE_FORMAT(printf, 1, 2);
443
391
VAR* var_from_env(const char *, const char *);
444
392
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
394
void var_free(void* v);
446
395
VAR* var_get(const char *var_name, const char** var_name_end,
447
396
bool raw, bool ignore_not_existing);
448
397
void eval_expr(VAR* v, const char *p, const char** p_end);
449
bool match_delimiter(int c, const char *delim, uint32_t length);
398
bool match_delimiter(int c, const char *delim, uint length);
450
399
void dump_result_to_reject_file(char *buf, int size);
451
void dump_result_to_log_file(const char *buf, int size);
452
void dump_warning_messages();
453
void dump_progress();
400
void dump_result_to_log_file(char *buf, int size);
401
void dump_warning_messages(void);
402
void dump_progress(void);
455
void do_eval(string *query_eval, const char *query,
404
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
456
405
const char *query_end, bool pass_through_escape_chars);
457
void str_to_file(const char *fname, const char *str, int size);
458
void str_to_file2(const char *fname, const char *str, int size, bool append);
406
void str_to_file(const char *fname, char *str, int size);
407
void str_to_file2(const char *fname, char *str, int size, bool append);
460
409
/* For replace_column */
461
410
static char *replace_column[MAX_COLUMNS];
462
static uint32_t max_replace_column= 0;
411
static uint max_replace_column= 0;
463
412
void do_get_replace_column(struct st_command*);
464
void free_replace_column();
413
void free_replace_column(void);
466
415
/* For replace */
467
416
void do_get_replace(struct st_command *command);
417
void free_replace(void);
470
419
/* For replace_regex */
471
420
void do_get_replace_regex(struct st_command *command);
473
void replace_append_mem(string *ds, const char *val,
475
void replace_append(string *ds, const char *val);
476
void replace_append_uint(string *ds, uint32_t val);
477
void append_sorted(string* ds, string* ds_input);
421
void free_replace_regex(void);
424
void free_all_replace(void);
427
void free_all_replace(void){
429
free_replace_regex();
430
free_replace_column();
433
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
435
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
436
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
437
void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input);
479
439
void handle_error(struct st_command*,
480
440
unsigned int err_errno, const char *err_error,
481
const char *err_sqlstate, string *ds);
441
const char *err_sqlstate, DYNAMIC_STRING *ds);
482
442
void handle_no_error(struct st_command*);
485
void do_eval(string *query_eval, const char *query,
444
#ifdef EMBEDDED_LIBRARY
446
/* attributes of the query thread */
447
pthread_attr_t cn_thd_attrib;
450
send_one_query executes query in separate thread, which is
451
necessary in embedded library to run 'send' in proper way.
452
This implementation doesn't handle errors returned
453
by mysql_send_query. It's technically possible, though
454
I don't see where it is needed.
456
pthread_handler_t send_one_query(void *arg)
458
struct st_connection *cn= (struct st_connection*)arg;
461
VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len));
464
pthread_mutex_lock(&cn->mutex);
466
VOID(pthread_cond_signal(&cn->cond));
467
pthread_mutex_unlock(&cn->mutex);
472
static int do_send_query(struct st_connection *cn, const char *q, int q_len,
477
if (flags & QUERY_REAP_FLAG)
478
return mysql_send_query(&cn->mysql, q, q_len);
480
if (pthread_mutex_init(&cn->mutex, NULL) ||
481
pthread_cond_init(&cn->cond, NULL))
482
die("Error in the thread library");
485
cn->cur_query_len= q_len;
487
if (pthread_create(&tid, &cn_thd_attrib, send_one_query, (void*)cn))
488
die("Cannot start new thread for query");
493
static void wait_query_thread_end(struct st_connection *con)
495
if (!con->query_done)
497
pthread_mutex_lock(&con->mutex);
498
while (!con->query_done)
499
pthread_cond_wait(&con->cond, &con->mutex);
500
pthread_mutex_unlock(&con->mutex);
504
#else /*EMBEDDED_LIBRARY*/
506
#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len)
508
#endif /*EMBEDDED_LIBRARY*/
510
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
486
511
const char *query_end, bool pass_through_escape_chars)
514
register char c, next_c;
515
register int escaped = 0;
492
for (const char *p= query; (c= *p) && p < query_end; ++p)
519
for (p= query; (c= *p) && p < query_end; ++p)
499
query_eval->append(p, 1);
526
dynstr_append_mem(query_eval, p, 1);
503
if (!(v= var_get(p, &p, 0, 0)))
504
die("Bad variable in eval");
505
query_eval->append(v->str_val, v->str_val_len);
530
if (!(v= var_get(p, &p, 0, 0)))
531
die("Bad variable in eval");
532
dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
513
query_eval->append(p, 1);
540
dynstr_append_mem(query_eval, p, 1);
515
542
else if (next_c == '\\' || next_c == '$' || next_c == '"')
517
544
/* Set escaped only if next char is \, " or $ */
520
547
if (pass_through_escape_chars)
522
549
/* The escape char should be added to the output string. */
523
query_eval->append(p, 1);
550
dynstr_append_mem(query_eval, p, 1);
527
query_eval->append(p, 1);
554
dynstr_append_mem(query_eval, p, 1);
531
query_eval->append(p, 1);
558
dynstr_append_mem(query_eval, p, 1);
3136
3170
when ndb binlog is on, this call will wait until last updated epoch
3137
(locally in the drizzled) has been received into the binlog
3171
(locally in the mysqld) has been received into the binlog
3139
static int do_save_master_pos()
3173
static int do_save_master_pos(void)
3141
drizzle_result_st res;
3142
drizzle_return_t ret;
3144
drizzle_con_st *con= &cur_con->con;
3177
MYSQL *mysql = &cur_con->mysql;
3145
3178
const char *query;
3148
if (drizzle_query_str(con, &res, query= "show master status", &ret) == NULL ||
3149
ret != DRIZZLE_RETURN_OK)
3181
#ifdef HAVE_NDB_BINLOG
3183
Wait for ndb binlog to be up-to-date with all changes
3184
done on the local mysql server
3151
if (ret == DRIZZLE_RETURN_ERROR_CODE)
3187
ulong have_ndbcluster;
3188
if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'"))
3189
die("'%s' failed: %d %s", query,
3190
mysql_errno(mysql), mysql_error(mysql));
3191
if (!(res= mysql_store_result(mysql)))
3192
die("mysql_store_result() returned NULL for '%s'", query);
3193
if (!(row= mysql_fetch_row(res)))
3194
die("Query '%s' returned empty result", query);
3196
have_ndbcluster= strcmp("YES", row[1]) == 0;
3197
mysql_free_result(res);
3199
if (have_ndbcluster)
3153
die("failed in '%s': %d: %s", query, drizzle_result_error_code(&res),
3154
drizzle_result_error(&res));
3155
drizzle_result_free(&res);
3201
uint64_t start_epoch= 0, handled_epoch= 0,
3202
latest_epoch=0, latest_trans_epoch=0,
3203
latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0,
3204
latest_applied_binlog_epoch= 0;
3209
const char binlog[]= "binlog";
3210
const char latest_epoch_str[]=
3212
const char latest_trans_epoch_str[]=
3213
"latest_trans_epoch=";
3214
const char latest_received_binlog_epoch_str[]=
3215
"latest_received_binlog_epoch";
3216
const char latest_handled_binlog_epoch_str[]=
3217
"latest_handled_binlog_epoch=";
3218
const char latest_applied_binlog_epoch_str[]=
3219
"latest_applied_binlog_epoch=";
3222
if (mysql_query(mysql, query= "show engine ndb status"))
3223
die("failed in '%s': %d %s", query,
3224
mysql_errno(mysql), mysql_error(mysql));
3225
if (!(res= mysql_store_result(mysql)))
3226
die("mysql_store_result() returned NULL for '%s'", query);
3227
while ((row= mysql_fetch_row(res)))
3229
if (strcmp(row[1], binlog) == 0)
3231
const char *status= row[2];
3234
while (*status && strncmp(status, latest_epoch_str,
3235
sizeof(latest_epoch_str)-1))
3239
status+= sizeof(latest_epoch_str)-1;
3240
latest_epoch= strtoull(status, (char**) 0, 10);
3243
die("result does not contain '%s' in '%s'",
3244
latest_epoch_str, query);
3245
/* latest_trans_epoch */
3246
while (*status && strncmp(status, latest_trans_epoch_str,
3247
sizeof(latest_trans_epoch_str)-1))
3251
status+= sizeof(latest_trans_epoch_str)-1;
3252
latest_trans_epoch= strtoull(status, (char**) 0, 10);
3255
die("result does not contain '%s' in '%s'",
3256
latest_trans_epoch_str, query);
3257
/* latest_received_binlog_epoch */
3259
strncmp(status, latest_received_binlog_epoch_str,
3260
sizeof(latest_received_binlog_epoch_str)-1))
3264
status+= sizeof(latest_received_binlog_epoch_str)-1;
3265
latest_received_binlog_epoch= strtoull(status, (char**) 0, 10);
3268
die("result does not contain '%s' in '%s'",
3269
latest_received_binlog_epoch_str, query);
3270
/* latest_handled_binlog */
3272
strncmp(status, latest_handled_binlog_epoch_str,
3273
sizeof(latest_handled_binlog_epoch_str)-1))
3277
status+= sizeof(latest_handled_binlog_epoch_str)-1;
3278
latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10);
3281
die("result does not contain '%s' in '%s'",
3282
latest_handled_binlog_epoch_str, query);
3283
/* latest_applied_binlog_epoch */
3285
strncmp(status, latest_applied_binlog_epoch_str,
3286
sizeof(latest_applied_binlog_epoch_str)-1))
3290
status+= sizeof(latest_applied_binlog_epoch_str)-1;
3291
latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10);
3294
die("result does not contain '%s' in '%s'",
3295
latest_applied_binlog_epoch_str, query);
3297
start_epoch= latest_trans_epoch;
3302
die("result does not contain '%s' in '%s'",
3304
if (latest_handled_binlog_epoch > handled_epoch)
3306
handled_epoch= latest_handled_binlog_epoch;
3308
if (latest_handled_binlog_epoch >= start_epoch)
3310
else if (count > 30)
3314
mysql_free_result(res);
3158
die("failed in '%s': %d: %s", query, ret, drizzle_con_error(con));
3319
if (mysql_query(mysql, query= "show master status"))
3320
die("failed in 'show master status': %d %s",
3321
mysql_errno(mysql), mysql_error(mysql));
3161
if (drizzle_result_column_count(&res) == 0 ||
3162
drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3163
die("drizzleclient_store_result() retuned NULL for '%s'", query);
3164
if (!(row = drizzle_row_next(&res)))
3323
if (!(res = mysql_store_result(mysql)))
3324
die("mysql_store_result() retuned NULL for '%s'", query);
3325
if (!(row = mysql_fetch_row(res)))
3165
3326
die("empty result in show master status");
3166
strncpy(master_pos.file, row[0], sizeof(master_pos.file)-1);
3327
strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
3167
3328
master_pos.pos = strtoul(row[1], (char**) 0, 10);
3168
drizzle_result_free(&res);
3329
mysql_free_result(res);
3318
3475
command->last_argument= p;
3319
charset_info= get_charset_by_csname(charset_name, MY_CS_PRIMARY);
3476
charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME));
3320
3477
if (!charset_info)
3321
3478
abort_not_supported_test("Test requires charset '%s'", charset_name);
3324
static void fill_global_error_names()
3326
drizzle_result_st res;
3327
drizzle_return_t ret;
3329
drizzle_con_st *con= &cur_con->con;
3331
global_error_names.clear();
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)
3338
if (ret == DRIZZLE_RETURN_ERROR_CODE)
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);
3346
die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3347
drizzle_con_error(con));
3350
if (drizzle_result_column_count(&res) == 0 ||
3351
drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3353
drizzle_result_free(&res);
3354
die("Query '%s' didn't return a result set", ds_query.c_str());
3357
while ((row= drizzle_row_next(&res)) && row[0])
3482
#if MYSQL_VERSION_ID >= 50000
3483
/* List of error names to error codes, available from 5.0 */
3490
static st_error global_error_names[] =
3492
#include <mysqld_ername.h>
3496
static uint get_errcode_from_name(char *error_name, char *error_end)
3498
/* SQL error as string */
3499
st_error *e= global_error_names;
3501
/* Loop through the array of known error names */
3502
for (; e->name; e++)
3360
Concatenate all fields in the first row with tab in between
3361
and assign that string to the $variable
3505
If we get a match, we need to check the length of the name we
3506
matched against in case it was longer than what we are checking
3507
(as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT).
3363
size_t *lengths= drizzle_row_field_sizes(&res);
3366
global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
3368
catch (boost::bad_lexical_cast &ex)
3370
drizzle_result_free(&res);
3371
die("Invalid error_code from Drizzle: %s", ex.what());
3509
if (!strncmp(error_name, e->name, (int) (error_end - error_name)) &&
3510
(uint) strlen(e->name) == (uint) (error_end - error_name))
3376
drizzle_result_free(&res);
3516
die("Unknown SQL error name '%s'", error_name);
3379
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
3520
uint get_errcode_from_name(char *error_name __attribute__((unused)),
3521
char *error_end __attribute__((unused)))
3381
size_t err_name_len= error_end - error_name;
3382
string error_name_s(error_name, err_name_len);
3384
ErrorCodes::iterator it= global_error_names.find(error_name_s);
3385
if (it != global_error_names.end())
3388
die("Unknown SQL error name '%s'", error_name_s.c_str());
3523
abort_not_in_this_version();
3524
return 0; /* Never reached */
3392
3530
static void do_get_errcodes(struct st_command *command)
3394
3532
struct st_match_err *to= saved_expected_errors.err;
3395
3533
char *p= command->first_argument;
3817
3963
<port> - server port
3818
3964
<sock> - server socket
3819
3965
<opts> - options to use for the connection
3820
* SSL - use SSL if available
3821
* COMPRESS - use compression if available
3966
* SSL - use SSL if available
3967
* COMPRESS - use compression if available
3825
3971
static void do_connect(struct st_command *command)
3827
uint32_t con_port= opt_port;
3828
const char *con_options;
3973
int con_port= opt_port;
3975
bool con_ssl= 0, con_compress= 0;
3830
3976
struct st_connection* con_slot;
3832
string ds_connection_name;
3978
static DYNAMIC_STRING ds_connection_name;
3979
static DYNAMIC_STRING ds_host;
3980
static DYNAMIC_STRING ds_user;
3981
static DYNAMIC_STRING ds_password;
3982
static DYNAMIC_STRING ds_database;
3983
static DYNAMIC_STRING ds_port;
3984
static DYNAMIC_STRING ds_sock;
3985
static DYNAMIC_STRING ds_options;
3840
3986
const struct command_arg connect_args[] = {
3841
{ "connection name", ARG_STRING, true, &ds_connection_name, "Name of the connection" },
3842
{ "host", ARG_STRING, true, &ds_host, "Host to connect to" },
3843
{ "user", ARG_STRING, false, &ds_user, "User to connect as" },
3844
{ "passsword", ARG_STRING, false, &ds_password, "Password used when connecting" },
3845
{ "database", ARG_STRING, false, &ds_database, "Database to select after connect" },
3846
{ "port", ARG_STRING, false, &ds_port, "Port to connect to" },
3847
{ "socket", ARG_STRING, false, &ds_sock, "Socket to connect with" },
3848
{ "options", ARG_STRING, false, &ds_options, "Options to use while connecting" }
3987
{ "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" },
3988
{ "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" },
3989
{ "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
3990
{ "passsword", ARG_STRING, FALSE, &ds_password, "Password used when connecting" },
3991
{ "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" },
3992
{ "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" },
3993
{ "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" },
3994
{ "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" }
4540
4691
while (*p && my_isspace(charset_info, *p))
4543
if (!(command->query_buf= command->query= strdup(p)))
4694
if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME))))
4544
4695
die("Out of memory");
4546
4697
/* Calculate first word length(the command), terminated by space or ( */
4547
4698
p= command->query;
4548
4699
while (*p && !my_isspace(charset_info, *p) && *p != '(')
4550
command->first_word_len= (uint32_t) (p - command->query);
4701
command->first_word_len= (uint) (p - command->query);
4552
4703
/* Skip spaces between command and first argument */
4553
4704
while (*p && my_isspace(charset_info, *p))
4555
4706
command->first_argument= p;
4557
command->end= strchr(command->query, '\0');
4708
command->end= strend(command->query);
4558
4709
command->query_len= (command->end - command->query);
4559
4710
parser.read_lines++;
4715
static struct my_option my_long_options[] =
4717
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
4719
{"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
4720
(char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4721
{"character-sets-dir", OPT_CHARSETS_DIR,
4722
"Directory where character sets are.", (char**) &opt_charsets_dir,
4723
(char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4724
{"compress", 'C', "Use the compressed server/client protocol.",
4725
(char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
4727
{"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
4728
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4729
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
4730
(char**) &debug_check_flag, (char**) &debug_check_flag, 0,
4731
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4732
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
4733
(char**) &debug_info_flag, (char**) &debug_info_flag,
4734
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4735
{"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
4736
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4737
{"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
4738
(char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4739
{"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
4740
(char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4741
{"mark-progress", OPT_MARK_PROGRESS,
4742
"Write linenumber and elapsed time to <testname>.progress ",
4743
(char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
4744
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4745
{"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
4746
"Max number of connection attempts when connecting to server",
4747
(char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
4748
GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
4749
{"password", 'p', "Password to use when connecting to server.",
4750
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
4751
{"port", 'P', "Port number to use for connection or 0 for default to, in "
4752
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
4753
#if MYSQL_PORT_DEFAULT == 0
4756
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
4758
(char**) &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4759
{"quiet", 's', "Suppress all normal output.", (char**) &silent,
4760
(char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4761
{"record", 'r', "Record output of test_file into result file.",
4762
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
4763
{"result-file", 'R', "Read/Store result from/in this file.",
4764
(char**) &result_file_name, (char**) &result_file_name, 0,
4765
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4766
{"server-arg", 'A', "Send option value to embedded server as a parameter.",
4767
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4768
{"server-file", 'F', "Read embedded server arguments from file.",
4769
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4770
{"silent", 's', "Suppress all normal output. Synonym for --quiet.",
4771
(char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4772
{"sleep", 'T', "Sleep always this many seconds on sleep commands.",
4773
(char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
4775
{"tail-lines", OPT_TAIL_LINES,
4776
"Number of lines of the resul to include in a failure report",
4777
(char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
4778
GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
4779
{"test-file", 'x', "Read test from/in this file (default stdin).",
4780
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4781
{"timer-file", 'm', "File where the timing in micro seconds is stored.",
4782
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4783
{"tmpdir", 't', "Temporary directory where sockets are put.",
4784
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4785
{"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
4786
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
4787
{"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
4788
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
4789
{"version", 'V', "Output version information and exit.",
4790
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
4791
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
4795
#include <help_start.h>
4797
static void print_version(void)
4799
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
4800
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
4803
static void usage(void)
4806
printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
4807
printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
4808
printf("Runs a test against the mysql server and compares output with a results file.\n\n");
4809
printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
4810
my_print_help(my_long_options);
4811
printf(" --no-defaults Don't read default options from any options file.\n");
4812
my_print_variables(my_long_options);
4815
#include <help_end.h>
4819
Read arguments for embedded server and put them into
4820
embedded_server_args[]
4823
static void read_embedded_server_arguments(const char *name)
4825
char argument[1024],buff[FN_REFLEN], *str=0;
4828
if (!test_if_hard_path(name))
4830
strxmov(buff, opt_basedir, name, NullS);
4833
fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
4835
if (!embedded_server_arg_count)
4837
embedded_server_arg_count=1;
4838
embedded_server_args[0]= (char*) ""; /* Progname */
4840
if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME))))
4841
die("Failed to open file '%s'", buff);
4843
while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
4844
(str=fgets(argument,sizeof(argument), file)))
4846
*(strend(str)-1)=0; /* Remove end newline */
4847
if (!(embedded_server_args[embedded_server_arg_count]=
4848
(char*) my_strdup(str,MYF(MY_WME))))
4850
my_fclose(file,MYF(0));
4851
die("Out of memory");
4854
embedded_server_arg_count++;
4856
my_fclose(file,MYF(0));
4858
die("Too many arguments in option file: %s",name);
4865
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
4874
char buff[FN_REFLEN];
4875
if (!test_if_hard_path(argument))
4877
strxmov(buff, opt_basedir, argument, NullS);
4880
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4881
assert(cur_file == file_stack && cur_file->file == 0);
4882
if (!(cur_file->file=
4883
my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
4884
die("Could not open '%s' for reading: errno = %d", buff, errno);
4885
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
4886
cur_file->lineno= 1;
4891
static char buff[FN_REFLEN];
4892
if (!test_if_hard_path(argument))
4894
strxmov(buff, opt_basedir, argument, NullS);
4897
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
4899
unlink(timer_file); /* Ignore error, may not exist */
4905
my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR));
4906
opt_pass= my_strdup(argument, MYF(MY_FAE));
4907
while (*argument) *argument++= 'x'; /* Destroy argument */
4914
strnmov(TMPDIR, argument, sizeof(TMPDIR));
4917
if (!embedded_server_arg_count)
4919
embedded_server_arg_count=1;
4920
embedded_server_args[0]= (char*) "";
4922
if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 ||
4923
!(embedded_server_args[embedded_server_arg_count++]=
4924
my_strdup(argument, MYF(MY_FAE))))
4926
die("Can't use server argument");
4930
read_embedded_server_arguments(argument);
4943
static int parse_args(int argc, char **argv)
4945
load_defaults("my",load_default_groups,&argc,&argv);
4948
if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
4959
opt_pass= get_tty_password(NullS); /* purify tested */
4960
if (debug_info_flag)
4961
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
4962
if (debug_check_flag)
4963
my_end_arg= MY_CHECK_ERROR;
4564
4969
Write the content of str into file
4739
5111
Append metadata for fields to output
4742
static void append_metadata(string *ds, drizzle_result_st *res)
5114
static void append_metadata(DYNAMIC_STRING *ds,
4744
drizzle_column_st *column;
4745
ds->append("Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
4746
"Column_alias\tType\tLength\tMax length\tIs_null\t"
4747
"Flags\tDecimals\tCharsetnr\n");
5118
MYSQL_FIELD *field_end;
5119
dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
5120
"Column_alias\tType\tLength\tMax length\tIs_null\t"
5121
"Flags\tDecimals\tCharsetnr\n");
4749
drizzle_column_seek(res, 0);
4750
while ((column= drizzle_column_next(res)))
5123
for (field_end= field+num_fields ;
4752
ds->append(drizzle_column_catalog(column),
4753
strlen(drizzle_column_catalog(column)));
4754
ds->append("\t", 1);
4755
ds->append(drizzle_column_db(column), strlen(drizzle_column_db(column)));
4756
ds->append("\t", 1);
4757
ds->append(drizzle_column_orig_table(column),
4758
strlen(drizzle_column_orig_table(column)));
4759
ds->append("\t", 1);
4760
ds->append(drizzle_column_table(column),
4761
strlen(drizzle_column_table(column)));
4762
ds->append("\t", 1);
4763
ds->append(drizzle_column_orig_name(column),
4764
strlen(drizzle_column_orig_name(column)));
4765
ds->append("\t", 1);
4766
ds->append(drizzle_column_name(column),
4767
strlen(drizzle_column_name(column)));
4768
ds->append("\t", 1);
4769
replace_append_uint(ds, drizzle_column_type_drizzle(column));
4770
ds->append("\t", 1);
4771
replace_append_uint(ds, drizzle_column_size(column));
4772
ds->append("\t", 1);
4773
if (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4775
replace_append_uint(ds, 1);
4779
replace_append_uint(ds, drizzle_column_max_size(column));
4781
ds->append("\t", 1);
4782
ds->append((char*) ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL) ? "N" : "Y"), 1);
4783
ds->append("\t", 1);
4784
replace_append_uint(ds, drizzle_column_flags(column));
4785
ds->append("\t", 1);
4786
replace_append_uint(ds, drizzle_column_decimals(column));
4787
ds->append("\t", 1);
4788
replace_append_uint(ds, drizzle_column_charset(column));
4789
ds->append("\n", 1);
5127
dynstr_append_mem(ds, field->catalog,
5128
field->catalog_length);
5129
dynstr_append_mem(ds, "\t", 1);
5130
dynstr_append_mem(ds, field->db, field->db_length);
5131
dynstr_append_mem(ds, "\t", 1);
5132
dynstr_append_mem(ds, field->org_table,
5133
field->org_table_length);
5134
dynstr_append_mem(ds, "\t", 1);
5135
dynstr_append_mem(ds, field->table,
5136
field->table_length);
5137
dynstr_append_mem(ds, "\t", 1);
5138
dynstr_append_mem(ds, field->org_name,
5139
field->org_name_length);
5140
dynstr_append_mem(ds, "\t", 1);
5141
dynstr_append_mem(ds, field->name, field->name_length);
5142
dynstr_append_mem(ds, "\t", 1);
5143
replace_dynstr_append_uint(ds, field->type);
5144
dynstr_append_mem(ds, "\t", 1);
5145
replace_dynstr_append_uint(ds, field->length);
5146
dynstr_append_mem(ds, "\t", 1);
5147
replace_dynstr_append_uint(ds, field->max_length);
5148
dynstr_append_mem(ds, "\t", 1);
5149
dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ?
5151
dynstr_append_mem(ds, "\t", 1);
5152
replace_dynstr_append_uint(ds, field->flags);
5153
dynstr_append_mem(ds, "\t", 1);
5154
replace_dynstr_append_uint(ds, field->decimals);
5155
dynstr_append_mem(ds, "\t", 1);
5156
replace_dynstr_append_uint(ds, field->charsetnr);
5157
dynstr_append_mem(ds, "\n", 1);
4836
5203
Number of warnings appended to ds
4839
static int append_warnings(string *ds, drizzle_con_st *con,
4840
drizzle_result_st *res)
5206
static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
4843
drizzle_result_st warn_res;
4844
drizzle_return_t ret;
4847
if (!(count= drizzle_result_warning_count(res)))
5209
MYSQL_RES *warn_res;
5212
if (!(count= mysql_warning_count(mysql)))
4850
if (drizzle_query_str(con, &warn_res, "SHOW WARNINGS", &ret) == NULL ||
4851
ret != DRIZZLE_RETURN_OK)
4853
if (ret == DRIZZLE_RETURN_ERROR_CODE)
4854
die("Error running query \"SHOW WARNINGS\": %s", drizzle_result_error(&warn_res));
4856
die("Error running query \"SHOW WARNINGS\": %s", drizzle_con_error(con));
4859
if (drizzle_result_column_count(&warn_res) == 0 ||
4860
drizzle_result_buffer(&warn_res) != DRIZZLE_RETURN_OK)
4861
die("Warning count is %u but didn't get any warnings", count);
4863
append_result(ds, &warn_res);
4864
drizzle_result_free(&warn_res);
5216
If one day we will support execution of multi-statements
5217
through PS API we should not issue SHOW WARNINGS until
5218
we have not read all results...
5220
assert(!mysql_more_results(mysql));
5222
if (mysql_real_query(mysql, "SHOW WARNINGS", 13))
5223
die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql));
5225
if (!(warn_res= mysql_store_result(mysql)))
5226
die("Warning count is %u but didn't get any warnings",
5229
append_result(ds, warn_res);
5230
mysql_free_result(warn_res);
4871
Run query using DRIZZLE C API
5237
Run query using MySQL C API
4875
drizzle DRIZZLE handle
4876
command current command pointer
4877
flags flags indicating if we should SEND and/or REAP
4878
query query string to execute
4879
query_len length query string to execute
4880
ds output buffer where to store result form query
5242
command current command pointer
5243
flags flags indicating if we should SEND and/or REAP
5244
query query string to execute
5245
query_len length query string to execute
5246
ds output buffer where to store result form query
4883
5249
static void run_query_normal(struct st_connection *cn,
4884
5250
struct st_command *command,
4885
5251
int flags, char *query, int query_len,
4886
string *ds, string *ds_warnings)
5252
DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
4888
drizzle_result_st res;
4889
drizzle_return_t ret;
4890
drizzle_con_st *con= &cn->con;
4893
drizzle_con_add_options(con, DRIZZLE_CON_NO_RESULT_READ);
5255
MYSQL *mysql= &cn->mysql;
5256
int err= 0, counter= 0;
4895
5258
if (flags & QUERY_SEND_FLAG)
4901
(void) drizzle_query(con, &res, query, query_len, &ret);
4902
if (ret != DRIZZLE_RETURN_OK)
5263
if (do_send_query(cn, query, query_len, flags))
4904
if (ret == DRIZZLE_RETURN_ERROR_CODE ||
4905
ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
4907
err= drizzle_result_error_code(&res);
4908
handle_error(command, err, drizzle_result_error(&res),
4909
drizzle_result_sqlstate(&res), ds);
4910
if (ret == DRIZZLE_RETURN_ERROR_CODE)
4911
drizzle_result_free(&res);
4915
handle_error(command, ret, drizzle_con_error(con), "", ds);
5265
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
5266
mysql_sqlstate(mysql), ds);
5270
#ifdef EMBEDDED_LIBRARY
5272
Here we handle 'reap' command, so we need to check if the
5273
query's thread was finished and probably wait
5275
else if (flags & QUERY_REAP_FLAG)
5276
wait_query_thread_end(cn);
5277
#endif /*EMBEDDED_LIBRARY*/
4921
5278
if (!(flags & QUERY_REAP_FLAG))
4926
* Read the result packet
4928
if (drizzle_result_read(con, &res, &ret) == NULL ||
4929
ret != DRIZZLE_RETURN_OK)
5284
When on first result set, call mysql_read_query_result to retrieve
5285
answer to the query sent earlier
5287
if ((counter==0) && mysql_read_query_result(mysql))
4931
if (ret == DRIZZLE_RETURN_ERROR_CODE)
4933
handle_error(command, drizzle_result_error_code(&res),
4934
drizzle_result_error(&res), drizzle_result_sqlstate(&res),
4938
handle_error(command, ret, drizzle_con_error(con), "", ds);
4939
drizzle_result_free(&res);
5289
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
5290
mysql_sqlstate(mysql), ds);
4945
5296
Store the result of the query if it will return any fields
4947
if (drizzle_result_column_count(&res) &&
4948
(ret= drizzle_result_buffer(&res)) != DRIZZLE_RETURN_OK)
5298
if (mysql_field_count(mysql) && ((res= mysql_store_result(mysql)) == 0))
4950
if (ret == DRIZZLE_RETURN_ERROR_CODE)
4952
handle_error(command, drizzle_result_error_code(&res),
4953
drizzle_result_error(&res), drizzle_result_sqlstate(&res),
4957
handle_error(command, ret, drizzle_con_error(con), "", ds);
4958
drizzle_result_free(&res);
5300
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
5301
mysql_sqlstate(mysql), ds);
5349
static void mark_progress(struct st_command*, int line)
5717
static void mark_progress(struct st_command* command __attribute__((unused)),
5351
5721
uint64_t timer= timer_now();
5352
5722
if (!progress_start)
5353
5723
progress_start= timer;
5354
5724
timer-= progress_start;
5357
5726
/* Milliseconds since start */
5358
buf << timer << "\t";
5727
end= int64_t2str(timer, buf, 10);
5728
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
5729
dynstr_append_mem(&ds_progress, "\t", 1);
5360
5731
/* Parser line number */
5361
buf << line << "\t";
5732
end= int10_to_str(line, buf, 10);
5733
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
5734
dynstr_append_mem(&ds_progress, "\t", 1);
5364
buf << cur_file->file_name << ":";
5737
dynstr_append(&ds_progress, cur_file->file_name);
5738
dynstr_append_mem(&ds_progress, ":", 1);
5366
5740
/* Line in file */
5367
buf << cur_file->lineno << endl;
5369
ds_progress.append(buf.str());
5373
static void check_retries(uint32_t in_opt_max_connect_retries)
5375
if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5377
cout << N_("Error: Invalid Value for opt_max_connect_retries");
5380
opt_max_connect_retries= in_opt_max_connect_retries;
5383
static void check_tail_lines(uint32_t in_opt_tail_lines)
5385
if (in_opt_tail_lines > 10000)
5387
cout << N_("Error: Invalid Value for opt_tail_lines");
5390
opt_tail_lines= in_opt_tail_lines;
5393
static void check_sleep(int32_t in_opt_sleep)
5395
if (in_opt_sleep < -1)
5397
cout << N_("Error: Invalid Value for opt_sleep");
5400
opt_sleep= in_opt_sleep;
5741
end= int10_to_str(cur_file->lineno, buf, 10);
5742
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
5745
dynstr_append_mem(&ds_progress, "\n", 1);
5403
5750
int main(int argc, char **argv)
5407
5752
struct st_command *command;
5408
5753
bool q_send_flag= 0, abort_flag= 0;
5409
uint32_t command_executed= 0, last_command_executed= 0;
5410
string save_file("");
5754
uint command_executed= 0, last_command_executed= 0;
5755
char save_file[FN_REFLEN];
5411
5756
struct stat res_info;
5415
internal::my_init();
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),
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")
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(""),
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")
5464
po::options_description client_options("Options specific to the client");
5465
client_options.add_options()
5467
("host,h", po::value<string>(&opt_host)->default_value("localhost"),
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(""),
5479
po::positional_options_description p;
5480
p.add("database", 1);
5482
po::options_description long_options("Allowed Options");
5483
long_options.add(commandline_options).add(test_options).add(client_options);
5485
std::string system_config_dir_test(SYSCONFDIR);
5486
system_config_dir_test.append("/drizzle/drizzletest.cnf");
5488
std::string system_config_dir_client(SYSCONFDIR);
5489
system_config_dir_client.append("/drizzle/client.cnf");
5491
std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5493
if (user_config_dir.compare(0, 2, "~/") == 0)
5495
const char *homedir= getenv("HOME");
5496
if (homedir != NULL)
5497
user_config_dir.replace(0, 1, homedir);
5500
po::variables_map vm;
5502
// Disable allow_guessing
5503
int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5505
po::store(po::command_line_parser(argc, argv).options(long_options).
5506
style(style).positional(p).extra_parser(parse_password_arg).run(),
5509
if (! vm["no-defaults"].as<bool>())
5511
std::string user_config_dir_test(user_config_dir);
5512
user_config_dir_test.append("/drizzle/drizzletest.cnf");
5514
std::string user_config_dir_client(user_config_dir);
5515
user_config_dir_client.append("/drizzle/client.cnf");
5517
ifstream user_test_ifs(user_config_dir_test.c_str());
5518
po::store(parse_config_file(user_test_ifs, test_options), vm);
5520
ifstream user_client_ifs(user_config_dir_client.c_str());
5521
po::store(parse_config_file(user_client_ifs, client_options), vm);
5523
ifstream system_test_ifs(system_config_dir_test.c_str());
5524
store(parse_config_file(system_test_ifs, test_options), vm);
5526
ifstream system_client_ifs(system_config_dir_client.c_str());
5527
po::store(parse_config_file(system_client_ifs, client_options), vm);
5532
5762
/* Init expected errors */
5533
5763
memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5560
5804
init_builtin_echo();
5562
ds_res.reserve(65536);
5563
ds_progress.reserve(2048);
5564
ds_warning_messages.reserve(2048);
5567
if (vm.count("record"))
5572
if (vm.count("test-file"))
5574
string tmp= vm["test-file"].as<string>();
5575
char buff[FN_REFLEN];
5576
if (!internal::test_if_hard_path(tmp.c_str()))
5578
snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
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")))
5585
fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5586
return EXIT_ARGUMENT_INVALID;
5588
if (!(cur_file->file_name= strdup(buff)))
5590
fprintf(stderr, _("Out of memory"));
5591
return EXIT_OUT_OF_MEMORY;
5593
cur_file->lineno= 1;
5596
if (vm.count("timer-file"))
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()))
5602
snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5605
internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5607
unlink(timer_file); /* Ignore error, may not exist */
5610
if (vm.count("protocol"))
5612
std::transform(opt_protocol.begin(), opt_protocol.end(),
5613
opt_protocol.begin(), ::tolower);
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;
5621
cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5626
if (vm.count("port"))
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
5631
if (opt_port > 65535)
5633
fprintf(stderr, _("Value supplied for port is not valid.\n"));
5634
exit(EXIT_ARGUMENT_INVALID);
5638
if( vm.count("password") )
5640
if (!opt_password.empty())
5641
opt_password.erase();
5642
if (password == PASSWORD_SENTINEL)
5648
opt_password= password;
5649
tty_password= false;
5657
if (vm.count("tmpdir"))
5659
strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
5662
if (vm.count("version"))
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);
5669
if (vm.count("help"))
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);
5683
opt_pass= client_get_tty_password(NULL); /* purify tested */
5806
init_dynamic_string(&ds_res, "", 65536, 65536);
5807
init_dynamic_string(&ds_progress, "", 0, 2048);
5808
init_dynamic_string(&ds_warning_messages, "", 0, 2048);
5809
parse_args(argc, argv);
5811
if (mysql_server_init(embedded_server_arg_count,
5812
embedded_server_args,
5813
(char**) embedded_server_groups))
5814
die("Can't initialize MySQL server");
5686
5815
server_initialized= 1;
5687
if (cur_file == file_stack.data() && cur_file->file == 0)
5816
if (cur_file == file_stack && cur_file->file == 0)
5689
5818
cur_file->file= stdin;
5690
cur_file->file_name= strdup("<stdin>");
5691
if (cur_file->file_name == NULL)
5692
die("Out of memory");
5819
cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
5693
5820
cur_file->lineno= 1;
5695
5822
cur_con= connections;
5696
if ((cur_con->drizzle= drizzle_create(NULL)) == NULL)
5697
die("Failed in drizzle_create()");
5698
if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5699
die("Failed in drizzle_con_create()");
5700
drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
5823
if (!( mysql_init(&cur_con->mysql)))
5824
die("Failed in mysql_init()");
5826
mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
5827
mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
5828
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME,
5829
charset_info->csname);
5830
int opt_protocol= MYSQL_PROTOCOL_TCP;
5831
mysql_options(&cur_con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
5832
if (opt_charsets_dir)
5833
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR,
5702
if (!(cur_con->name = strdup("default")))
5836
if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
5703
5837
die("Out of memory");
5704
safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
5839
safe_connect(&cur_con->mysql, cur_con->name, opt_host, opt_user, opt_pass,
5705
5840
opt_db, opt_port);
5707
fill_global_error_names();
5709
5842
/* Use all time until exit if no explicit 'start_timer' */
5710
5843
timer_start= timer_now();
5713
Initialize $drizzleclient_errno with -1, so we can
5846
Initialize $mysql_errno with -1, so we can
5714
5847
- distinguish it from valid values ( >= 0 ) and
5715
5848
- detect if there was never a command sent to the server
5717
5850
var_set_errno(-1);
5719
/* Update $drizzleclient_get_server_version to that of current connection */
5720
var_set_drizzleclient_get_server_version(&cur_con->con);
5852
/* Update $mysql_get_server_version to that of current connection */
5853
var_set_mysql_get_server_version(&cur_con->mysql);
5722
if (! opt_include.empty())
5724
open_file(opt_include.c_str());
5857
open_file(opt_include);
5727
5860
while (!read_command(&command) && !abort_flag)
6580
6721
icase - flag, if set to 1 the match is case insensitive
6582
6723
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
6583
char *replace, char *in_string, int icase, int global)
6724
char *replace, char *in_string, int icase)
6585
const char *error= NULL;
6588
pcre *re= pcre_compile(pattern,
6589
icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
6590
&error, &erroffset, NULL);
6597
int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6605
char *substring_to_replace= in_string + ovector[0];
6606
int substring_length= ovector[1] - ovector[0];
6607
*buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6608
char * new_buf = (char *)malloc(*buf_len_p+1);
6609
if (new_buf == NULL)
6615
memset(new_buf, 0, *buf_len_p+1);
6616
strncpy(new_buf, in_string, substring_to_replace-in_string);
6617
strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6618
strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6619
substring_to_replace + substring_length,
6622
- (substring_to_replace-in_string));
6630
/* Repeatedly replace the string with the matched regex */
6631
string subject(in_string);
6632
size_t replace_length= strlen(replace);
6633
size_t length_of_replacement= strlen(replace);
6634
size_t current_position= 0;
6639
rc= pcre_exec(re, NULL, subject.c_str(), subject.length(),
6640
current_position, 0, ovector, 3);
6646
current_position= static_cast<size_t>(ovector[0]);
6647
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;
6652
char *new_buf = (char *) malloc(subject.length() + 1);
6653
if (new_buf == NULL)
6658
memset(new_buf, 0, subject.length() + 1);
6659
strncpy(new_buf, subject.c_str(), subject.length());
6660
*buf_len_p= subject.length() + 1;
6726
string string_to_match(in_string);
6727
pcrecpp::RE_Options opt;
6730
opt.set_caseless(true);
6732
if (!pcrecpp::RE(pattern, opt).Replace(replace,&string_to_match)){
6736
const char * new_str= string_to_match.c_str();
6737
*buf_len_p= strlen(new_str);
6738
char * new_buf = (char *)malloc(*buf_len_p+1);
6739
if (new_buf == NULL)
6743
strcpy(new_buf, new_str);
6669
6750
#ifndef WORD_BIT
6670
#define WORD_BIT (8*sizeof(uint32_t))
6751
#define WORD_BIT (8*sizeof(uint))
6673
6754
#define SET_MALLOC_HUNC 64
6674
6755
#define LAST_CHAR_CODE 259
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;
6686
uint32_t *bits; /* Pointer to used sets */
6687
short next[LAST_CHAR_CODE]; /* Pointer to next sets */
6688
uint32_t found_len; /* Best match to date */
6690
uint32_t table_offset;
6691
uint32_t size_of_bits; /* For convinience */
6697
int find_set(const REP_SET *find);
6698
void free_last_set();
6700
void make_sets_invisible();
6702
uint32_t count; /* Number of sets */
6703
uint32_t extra; /* Extra sets in buffer */
6704
uint32_t invisible; /* Sets not shown */
6705
uint32_t size_of_bits;
6706
REP_SET *set,*set_buffer;
6707
uint32_t *bit_buffer;
6712
uint32_t table_offset;
6757
typedef struct st_rep_set {
6758
uint *bits; /* Pointer to used sets */
6759
short next[LAST_CHAR_CODE]; /* Pointer to next sets */
6760
uint found_len; /* Best match to date */
6763
uint size_of_bits; /* For convinience */
6766
typedef struct st_rep_sets {
6767
uint count; /* Number of sets */
6768
uint extra; /* Extra sets in buffer */
6769
uint invisible; /* Sets not chown */
6771
REP_SET *set,*set_buffer;
6775
typedef struct st_found_set {
6713
6777
int found_offset;
6780
typedef struct st_follow {
6719
uint32_t table_offset;
6723
int init_sets(REP_SETS *sets, uint32_t states);
6787
int init_sets(REP_SETS *sets,uint states);
6724
6788
REP_SET *make_new_set(REP_SETS *sets);
6725
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset);
6727
static uint32_t found_sets= 0;
6729
static uint32_t replace_len(const char *str)
6789
void make_sets_invisible(REP_SETS *sets);
6790
void free_last_set(REP_SETS *sets);
6791
void free_sets(REP_SETS *sets);
6792
void internal_set_bit(REP_SET *set, uint bit);
6793
void internal_clear_bit(REP_SET *set, uint bit);
6794
void or_bits(REP_SET *to,REP_SET *from);
6795
void copy_bits(REP_SET *to,REP_SET *from);
6796
int cmp_bits(REP_SET *set1,REP_SET *set2);
6797
int get_next_bit(REP_SET *set,uint lastpos);
6798
int find_set(REP_SETS *sets,REP_SET *find);
6799
int find_found(FOUND_SET *found_set,uint table_offset,
6801
uint start_at_word(char * pos);
6802
uint end_of_word(char * pos);
6804
static uint found_sets=0;
6807
static uint replace_len(char * str)
6734
6812
if (str[0] == '\\' && str[1])
6778
result_len+=(uint32_t) strlen(to[i])+1;
6851
result_len+=(uint) strlen(to[i])+1;
6779
6852
if (len > max_length)
6780
6853
max_length=len;
6782
memset(is_word_end, 0, sizeof(is_word_end));
6855
bzero((char*) is_word_end,sizeof(is_word_end));
6783
6856
for (i=0 ; word_end_chars[i] ; i++)
6784
is_word_end[(unsigned char) word_end_chars[i]]=1;
6857
is_word_end[(uchar) word_end_chars[i]]=1;
6787
REP_SET *set,*start_states,*word_states,*new_set;
6788
REPLACE_STRING *rep_str;
6789
if (init_sets(&sets, states))
6859
if (init_sets(&sets,states))
6792
vector<FOUND_SET> found_set(max_length * count);
6793
make_new_set(&sets); /* Set starting set */
6794
sets.make_sets_invisible(); /* Hide previus sets */
6862
if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
6868
VOID(make_new_set(&sets)); /* Set starting set */
6869
make_sets_invisible(&sets); /* Hide previus sets */
6796
word_states=make_new_set(&sets); /* Start of new word */
6797
start_states=make_new_set(&sets); /* This is first state */
6798
vector<FOLLOWS> follow(states + 2);
6799
FOLLOWS *follow_ptr= &follow[1];
6871
word_states=make_new_set(&sets); /* Start of new word */
6872
start_states=make_new_set(&sets); /* This is first state */
6873
if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
6876
my_free(found_set,MYF(0));
6800
6880
/* Init follow_ptr[] */
6801
for (i=0, states=1; i < count; i++)
6881
for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
6803
6883
if (from[i][0] == '\\' && from[i][1] == '^')
6805
start_states->internal_set_bit(states + 1);
6885
internal_set_bit(start_states,states+1);
6806
6886
if (!from[i][2])
6808
start_states->table_offset=i;
6809
start_states->found_offset=1;
6888
start_states->table_offset=i;
6889
start_states->found_offset=1;
6812
6892
else if (from[i][0] == '\\' && from[i][1] == '$')
6814
start_states->internal_set_bit(states);
6815
word_states->internal_set_bit(states);
6816
if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6894
internal_set_bit(start_states,states);
6895
internal_set_bit(word_states,states);
6896
if (!from[i][2] && start_states->table_offset == (uint) ~0)
6818
start_states->table_offset=i;
6819
start_states->found_offset=0;
6898
start_states->table_offset=i;
6899
start_states->found_offset=0;
6824
word_states->internal_set_bit(states);
6904
internal_set_bit(word_states,states);
6825
6905
if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
6826
start_states->internal_set_bit(states + 1);
6906
internal_set_bit(start_states,states+1);
6828
start_states->internal_set_bit(states);
6908
internal_set_bit(start_states,states);
6831
for (pos= from[i], len=0; *pos ; pos++)
6910
for (pos=from[i], len=0; *pos ; pos++)
6833
6912
if (*pos == '\\' && *(pos+1))
6838
follow_ptr->chr = SPACE_CHAR;
6841
follow_ptr->chr = START_OF_LINE;
6844
follow_ptr->chr = END_OF_LINE;
6847
follow_ptr->chr = '\r';
6850
follow_ptr->chr = '\t';
6853
follow_ptr->chr = '\v';
6856
follow_ptr->chr = (unsigned char) *pos;
6917
follow_ptr->chr = SPACE_CHAR;
6920
follow_ptr->chr = START_OF_LINE;
6923
follow_ptr->chr = END_OF_LINE;
6926
follow_ptr->chr = '\r';
6929
follow_ptr->chr = '\t';
6932
follow_ptr->chr = '\v';
6935
follow_ptr->chr = (uchar) *pos;
6861
follow_ptr->chr= (unsigned char) *pos;
6940
follow_ptr->chr= (uchar) *pos;
6862
6941
follow_ptr->table_offset=i;
6863
6942
follow_ptr->len= ++len;
6867
6946
follow_ptr->table_offset=i;
6868
6947
follow_ptr->len=len;
6870
states+=(uint32_t) len+1;
6949
states+=(uint) len+1;
6874
for (set_nr=0; set_nr < sets.count ; set_nr++)
6953
for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6876
6955
set=sets.set+set_nr;
6877
default_state= 0; /* Start from beginning */
6956
default_state= 0; /* Start from beginning */
6879
6958
/* If end of found-string not found or start-set with current set */
6881
for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
6960
for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
6883
if (!follow[i].chr && !default_state)
6884
default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
6964
if (! default_state)
6965
default_state= find_found(found_set,set->table_offset,
6966
set->found_offset+1);
6886
sets.set[used_sets].copy_bits(set); /* Save set for changes */
6969
copy_bits(sets.set+used_sets,set); /* Save set for changes */
6887
6970
if (!default_state)
6888
sets.set[used_sets].or_bits(sets.set); /* Can restart from start */
6971
or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
6890
6973
/* Find all chars that follows current sets */
6891
memset(used_chars, 0, sizeof(used_chars));
6892
for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i)) ;)
6974
bzero((char*) used_chars,sizeof(used_chars));
6975
for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
6894
6977
used_chars[follow[i].chr]=1;
6895
6978
if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6896
follow[i].len > 1) || follow[i].chr == END_OF_LINE)
6979
follow[i].len > 1) || follow[i].chr == END_OF_LINE)
6900
6983
/* Mark word_chars used if \b is in state */
6901
6984
if (used_chars[SPACE_CHAR])
6902
for (const char *pos= word_end_chars ; *pos ; pos++)
6903
used_chars[(int) (unsigned char) *pos] = 1;
6985
for (pos= word_end_chars ; *pos ; pos++)
6986
used_chars[(int) (uchar) *pos] = 1;
6905
6988
/* Handle other used characters */
6906
6989
for (chr= 0 ; chr < 256 ; chr++)
6908
6991
if (! used_chars[chr])
6909
set->next[chr]= chr ? default_state : -1;
6992
set->next[chr]= chr ? default_state : -1;
6912
new_set=make_new_set(&sets);
6913
set=sets.set+set_nr; /* if realloc */
6914
new_set->table_offset=set->table_offset;
6915
new_set->found_len=set->found_len;
6916
new_set->found_offset=set->found_offset+1;
6995
new_set=make_new_set(&sets);
6996
set=sets.set+set_nr; /* if realloc */
6997
new_set->table_offset=set->table_offset;
6998
new_set->found_len=set->found_len;
6999
new_set->found_offset=set->found_offset+1;
6919
for (i= UINT32_MAX ; (i= sets.set[used_sets].get_next_bit(i)) ; )
6921
if (!follow[i].chr || follow[i].chr == chr ||
6922
(follow[i].chr == SPACE_CHAR &&
6923
(is_word_end[chr] ||
6924
(!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
6925
(follow[i].chr == END_OF_LINE && ! chr))
6927
if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
6928
follow[i].len > found_end)
6929
found_end=follow[i].len;
6930
if (chr && follow[i].chr)
6931
new_set->internal_set_bit(i + 1); /* To next set */
6933
new_set->internal_set_bit(i);
6938
new_set->found_len=0; /* Set for testing if first */
6940
for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
6942
if ((follow[i].chr == SPACE_CHAR ||
6943
follow[i].chr == END_OF_LINE) && ! chr)
6947
if (follow[bit_nr-1].len < found_end ||
6948
(new_set->found_len &&
6949
(chr == 0 || !follow[bit_nr].chr)))
6950
new_set->internal_clear_bit(i);
6953
if (chr == 0 || !follow[bit_nr].chr)
6955
new_set->table_offset=follow[bit_nr].table_offset;
6956
if (chr || (follow[i].chr == SPACE_CHAR ||
6957
follow[i].chr == END_OF_LINE))
6958
new_set->found_offset=found_end; /* New match */
6959
new_set->found_len=found_end;
6966
set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6967
sets.free_last_set();
6970
set->next[chr] = sets.find_set(new_set);
6973
set->next[chr] = sets.find_set(new_set);
7002
for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
7004
if (!follow[i].chr || follow[i].chr == chr ||
7005
(follow[i].chr == SPACE_CHAR &&
7006
(is_word_end[chr] ||
7007
(!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
7008
(follow[i].chr == END_OF_LINE && ! chr))
7010
if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
7011
follow[i].len > found_end)
7012
found_end=follow[i].len;
7013
if (chr && follow[i].chr)
7014
internal_set_bit(new_set,i+1); /* To next set */
7016
internal_set_bit(new_set,i);
7021
new_set->found_len=0; /* Set for testing if first */
7023
for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
7025
if ((follow[i].chr == SPACE_CHAR ||
7026
follow[i].chr == END_OF_LINE) && ! chr)
7030
if (follow[bit_nr-1].len < found_end ||
7031
(new_set->found_len &&
7032
(chr == 0 || !follow[bit_nr].chr)))
7033
internal_clear_bit(new_set,i);
7036
if (chr == 0 || !follow[bit_nr].chr)
7038
new_set->table_offset=follow[bit_nr].table_offset;
7039
if (chr || (follow[i].chr == SPACE_CHAR ||
7040
follow[i].chr == END_OF_LINE))
7041
new_set->found_offset=found_end; /* New match */
7042
new_set->found_len=found_end;
7049
set->next[chr] = find_found(found_set,
7050
new_set->table_offset,
7051
new_set->found_offset);
7052
free_last_set(&sets);
7055
set->next[chr] = find_set(&sets,new_set);
7058
set->next[chr] = find_set(&sets,new_set);
6978
7063
/* Alloc replace structure for the replace-state-machine */
6980
REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
+ sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
7065
if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
7066
sizeof(REPLACE_STRING)*(found_sets+1)+
7067
sizeof(char *)*count+result_len,
7068
MYF(MY_WME | MY_ZEROFILL))))
6984
memset(replace, 0, sizeof(REPLACE)*(sets.count)+
6985
sizeof(REPLACE_STRING)*(found_sets+1)+
6986
sizeof(char *)*count+result_len);
6987
7070
rep_str=(REPLACE_STRING*) (replace+sets.count);
6988
7071
to_array= (char **) (rep_str+found_sets+1);
6989
7072
to_pos=(char *) (to_array+count);
6990
7073
for (i=0 ; i < count ; i++)
6992
7075
to_array[i]=to_pos;
6993
to_pos=strcpy(to_pos,to[i])+strlen(to[i])+1;
7076
to_pos=strmov(to_pos,to[i])+1;
6995
7078
rep_str[0].found=1;
6996
7079
rep_str[0].replace_string=0;
6997
7080
for (i=1 ; i <= found_sets ; i++)
6999
const char *pos= from[found_set[i-1].table_offset];
7000
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);
7082
pos=from[found_set[i-1].table_offset];
7083
rep_str[i].found= !bcmp((const uchar*) pos,
7084
(const uchar*) "\\^", 3) ? 2 : 1;
7085
rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
7086
rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
7087
rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
7005
7090
for (i=0 ; i < sets.count ; i++)
7007
7092
for (j=0 ; j < 256 ; j++)
7008
if (sets.set[i].next[j] >= 0)
7009
replace[i].next[j]=replace+sets.set[i].next[j];
7011
replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7093
if (sets.set[i].next[j] >= 0)
7094
replace[i].next[j]=replace+sets.set[i].next[j];
7096
replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7099
my_free(follow,MYF(0));
7101
my_free(found_set,MYF(0));
7019
int init_sets(REP_SETS *sets,uint32_t states)
7106
int init_sets(REP_SETS *sets,uint states)
7021
memset(sets, 0, sizeof(*sets));
7108
bzero((char*) sets,sizeof(*sets));
7022
7109
sets->size_of_bits=((states+7)/8);
7023
if (!(sets->set_buffer=(REP_SET*) malloc(sizeof(REP_SET)*SET_MALLOC_HUNC)))
7110
if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
7025
if (!(sets->bit_buffer=(uint*) malloc(sizeof(uint32_t)*sets->size_of_bits*
7113
if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
7114
SET_MALLOC_HUNC,MYF(MY_WME))))
7116
my_free(sets->set,MYF(0));
7160
7261
set->next[] == -1 is reserved for end without replaces.
7163
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
7264
int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
7166
for (; i < found_sets; i++)
7267
for (i=0 ; (uint) i < found_sets ; i++)
7168
7268
if (found_set[i].table_offset == table_offset &&
7169
found_set[i].found_offset == found_offset)
7172
found_set[i].table_offset= table_offset;
7173
found_set[i].found_offset= found_offset;
7269
found_set[i].found_offset == found_offset)
7271
found_set[i].table_offset=table_offset;
7272
found_set[i].found_offset=found_offset;
7175
return - i - 2; // return new postion
7274
return -i-2; /* return new postion */
7277
/* Return 1 if regexp starts with \b or ends with \b*/
7279
uint start_at_word(char * pos)
7281
return (((!bcmp((const uchar*) pos, (const uchar*) "\\b",2) && pos[2]) ||
7282
!bcmp((const uchar*) pos, (const uchar*) "\\^", 2)) ? 1 : 0);
7285
uint end_of_word(char * pos)
7287
char * end=strend(pos);
7288
return ((end > pos+2 && !bcmp((const uchar*) end-2,
7289
(const uchar*) "\\b", 2)) ||
7290
(end >= pos+2 && !bcmp((const uchar*) end-2,
7291
(const uchar*) "\\$",2))) ? 1 : 0;
7178
7294
/****************************************************************************
7179
7295
* Handle replacement of strings
7180
7296
****************************************************************************/
7182
#define PC_MALLOC 256 /* Bytes for pointers */
7183
#define PS_MALLOC 512 /* Bytes for data */
7298
#define PC_MALLOC 256 /* Bytes for pointers */
7299
#define PS_MALLOC 512 /* Bytes for data */
7185
7301
int insert_pointer_name(POINTER_ARRAY *pa,char * name)
7187
uint32_t i,length,old_count;
7188
unsigned char *new_pos;
7303
uint i,length,old_count;
7189
7305
const char **new_array;
7192
7308
if (! pa->typelib.count)
7194
7310
if (!(pa->typelib.type_names=(const char **)
7195
malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
7196
(sizeof(char *)+sizeof(*pa->flag))*
7197
(sizeof(char *)+sizeof(*pa->flag))))))
7311
my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
7312
(sizeof(char *)+sizeof(*pa->flag))*
7313
(sizeof(char *)+sizeof(*pa->flag))),MYF(MY_WME))))
7199
if (!(pa->str= (unsigned char*) malloc(PS_MALLOC-MALLOC_OVERHEAD)))
7315
if (!(pa->str= (uchar*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
7201
free((char*) pa->typelib.type_names);
7318
my_free((char*) pa->typelib.type_names,MYF(0));
7204
pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(unsigned char*)+
7206
pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
7321
pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(uchar*)+
7323
pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
7208
7325
pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
7209
7326
pa->array_allocs=1;
7211
length=(uint32_t) strlen(name)+1;
7328
length=(uint) strlen(name)+1;
7212
7329
if (pa->length+length >= pa->max_length)
7214
if (!(new_pos= (unsigned char*)realloc((unsigned char*)pa->str,
7215
(size_t)(pa->max_length+PS_MALLOC))))
7331
if (!(new_pos= (uchar*) my_realloc((uchar*) pa->str,
7332
(uint) (pa->max_length+PS_MALLOC),
7217
7335
if (new_pos != pa->str)
7219
ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
7337
my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
7220
7338
for (i=0 ; i < pa->typelib.count ; i++)
7221
pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
7339
pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
7223
7341
pa->str=new_pos;
7225
7343
pa->max_length+=PS_MALLOC;
7227
7345
if (pa->typelib.count >= pa->max_count-1)
7230
7348
pa->array_allocs++;
7231
7349
len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
7233
(const char **)realloc((unsigned char*) pa->typelib.type_names,
7235
(sizeof(unsigned char*)+sizeof(*pa->flag))*
7236
(sizeof(unsigned char*)+sizeof(*pa->flag)))))
7350
if (!(new_array=(const char **) my_realloc((uchar*) pa->typelib.type_names,
7352
(sizeof(uchar*)+sizeof(*pa->flag))*
7353
(sizeof(uchar*)+sizeof(*pa->flag)),
7238
7356
pa->typelib.type_names=new_array;
7239
7357
old_count=pa->max_count;
7240
pa->max_count=len/(sizeof(unsigned char*) + sizeof(*pa->flag));
7241
pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
7242
memcpy(pa->flag, pa->typelib.type_names+old_count,
7243
old_count*sizeof(*pa->flag));
7358
pa->max_count=len/(sizeof(uchar*) + sizeof(*pa->flag));
7359
pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
7360
memcpy((uchar*) pa->flag,(char *) (pa->typelib.type_names+old_count),
7361
old_count*sizeof(*pa->flag));
7245
pa->flag[pa->typelib.count]=0; /* Reset flag */
7363
pa->flag[pa->typelib.count]=0; /* Reset flag */
7246
7364
pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length;
7247
pa->typelib.type_names[pa->typelib.count]= NULL; /* Put end-mark */
7248
strcpy((char*) pa->str+pa->length,name);
7365
pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
7366
VOID(strmov((char*) pa->str+pa->length,name));
7249
7367
pa->length+=length;
7251
7369
} /* insert_pointer_name */
7372
/* free pointer array */
7374
void free_pointer_array(POINTER_ARRAY *pa)
7376
if (pa->typelib.count)
7378
pa->typelib.count=0;
7379
my_free((char*) pa->typelib.type_names,MYF(0));
7380
pa->typelib.type_names=0;
7381
my_free(pa->str,MYF(0));
7383
} /* free_pointer_array */
7254
7386
/* Functions that uses replace and replace_regex */
7256
7388
/* Append the string to ds, with optional replace */
7257
void replace_append_mem(string *ds, const char *val, int len)
7389
void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
7390
const char *val, int len)
7259
char *v= strdup(val);
7392
if (glob_replace_regex)
7395
if (!multi_reg_replace(glob_replace_regex, (char*)val))
7397
val= glob_replace_regex->buf;
7261
if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
7263
v= glob_replace_regex->buf_;
7266
7402
if (glob_replace)
7268
7404
/* Normal replace */
7269
replace_strings_append(glob_replace, ds, v, len);
7405
replace_strings_append(glob_replace, ds, val, len);
7408
dynstr_append_mem(ds, val, len);
7276
7412
/* Append zero-terminated string to ds, with optional replace */
7277
void replace_append(string *ds, const char *val)
7413
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
7279
replace_append_mem(ds, val, strlen(val));
7415
replace_dynstr_append_mem(ds, val, strlen(val));
7282
/* Append uint32_t to ds, with optional replace */
7283
void replace_append_uint(string *ds, uint32_t val)
7418
/* Append uint to ds, with optional replace */
7419
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val)
7287
replace_append_mem(ds, buff.str().c_str(), buff.str().size());
7421
char buff[22]; /* This should be enough for any int */
7422
char *end= int64_t10_to_str(val, buff, 10);
7423
replace_dynstr_append_mem(ds, buff, end - buff);