summaryrefslogtreecommitdiff
path: root/client/mysqltest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqltest.cc')
-rw-r--r--client/mysqltest.cc1698
1 files changed, 1176 insertions, 522 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index bfed483134a..01613223d64 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -12,8 +12,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
mysqltest
@@ -34,7 +33,7 @@
And many others
*/
-#define MTEST_VERSION "3.3"
+#define MTEST_VERSION "3.4"
#include "client_priv.h"
#include <mysql_version.h>
@@ -62,6 +61,12 @@
#define SIGNAL_FMT "signal %d"
#endif
+static my_bool non_blocking_api_enabled= 0;
+#if !defined(EMBEDDED_LIBRARY)
+#define WRAP_NONBLOCK_ENABLED non_blocking_api_enabled
+#include "../tests/nonblock-wrappers.h"
+#endif
+
/* Use cygwin for --exec and --system before 5.0 */
#if MYSQL_VERSION_ID < 50000
#define USE_CYGWIN
@@ -73,6 +78,8 @@
#define MAX_DELIMITER_LENGTH 16
#define DEFAULT_MAX_CONN 64
+#define DIE_BUFF_SIZE 8192
+
/* Flags controlling send and reap */
#define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2
@@ -81,27 +88,28 @@
static int setenv(const char *name, const char *value, int overwrite);
#endif
+C_MODE_START
+static sig_handler signal_handler(int sig);
+static my_bool get_one_option(int optid, const struct my_option *,
+ char *argument);
+C_MODE_END
+
enum {
- OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION,
- OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
- OPT_MAX_CONNECT_RETRIES, OPT_MAX_CONNECTIONS,
- OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
- OPT_GLOBAL_SUBST, OPT_MY_CONNECT_TIMEOUT
+ OPT_LOG_DIR=OPT_MAX_CLIENT_OPTION, OPT_RESULT_FORMAT_VERSION
};
static int record= 0, opt_sleep= -1;
static char *opt_db= 0, *opt_pass= 0;
const char *opt_user= 0, *opt_host= 0, *unix_sock= 0, *opt_basedir= "./";
-#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
-#endif
const char *opt_logdir= "";
-const char *opt_include= 0, *opt_charsets_dir;
+const char *opt_prologue= 0, *opt_charsets_dir;
static int opt_port= 0;
static int opt_max_connect_retries;
+static int opt_result_format_version;
static int opt_max_connections= DEFAULT_MAX_CONN;
+static int error_count= 0;
static my_bool opt_compress= 0, silent= 0, verbose= 0;
-static int opt_connect_timeout= -1;
static my_bool debug_info_flag= 0, debug_check_flag= 0;
static my_bool tty_password= 0;
static my_bool opt_mark_progress= 0;
@@ -117,8 +125,7 @@ static my_bool disable_connect_log= 1;
static my_bool disable_warnings= 0, disable_column_names= 0;
static my_bool prepare_warnings_enabled= 0;
static my_bool disable_info= 1;
-static char *opt_plugin_dir= 0, *opt_default_auth;
-static my_bool abort_on_error= 1;
+static my_bool abort_on_error= 1, opt_continue_on_error= 0;
static my_bool server_initialized= 0;
static my_bool is_windows= 0;
static char **default_argv;
@@ -126,12 +133,49 @@ static const char *load_default_groups[]=
{ "mysqltest", "client", "client-server", "client-mariadb", 0 };
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
+/* Info on properties that can be set with --enable_X and --disable_X */
+
+struct property {
+ my_bool *var; /* Actual variable */
+ my_bool set; /* Has been set for ONE command */
+ my_bool old; /* If set, thus is the old value */
+ my_bool reverse; /* Varible is true if disabled */
+ const char *env_name; /* Env. variable name */
+};
+
+static struct property prop_list[] = {
+ { &abort_on_error, 0, 1, 0, "$ENABLED_ABORT_ON_ERROR" },
+ { &disable_connect_log, 0, 1, 1, "$ENABLED_CONNECT_LOG" },
+ { &disable_info, 0, 1, 1, "$ENABLED_INFO" },
+ { &display_metadata, 0, 0, 0, "$ENABLED_METADATA" },
+ { &ps_protocol_enabled, 0, 0, 0, "$ENABLED_PS_PROTOCOL" },
+ { &disable_query_log, 0, 0, 1, "$ENABLED_QUERY_LOG" },
+ { &disable_result_log, 0, 0, 1, "$ENABLED_RESULT_LOG" },
+ { &disable_warnings, 0, 0, 1, "$ENABLED_WARNINGS" }
+};
+
+static my_bool once_property= FALSE;
+
+enum enum_prop {
+ P_ABORT= 0,
+ P_CONNECT,
+ P_INFO,
+ P_META,
+ P_PS,
+ P_QUERY,
+ P_RESULT,
+ P_WARN,
+ P_MAX
+};
+
static uint start_lineno= 0; /* Start line of current command */
static uint my_end_arg= 0;
/* Number of lines of the result to include in failure report */
static uint opt_tail_lines= 0;
+static uint opt_connect_timeout= 0;
+
static char delimiter[MAX_DELIMITER_LENGTH]= ";";
static uint delimiter_length= 1;
@@ -163,7 +207,7 @@ static struct st_block *cur_block, *block_stack_end;
struct st_test_file
{
FILE* file;
- const char *file_name;
+ char *file_name;
uint lineno; /* Current line in file */
};
@@ -171,7 +215,6 @@ static struct st_test_file file_stack[16];
static struct st_test_file* cur_file;
static struct st_test_file* file_stack_end;
-
static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */
static const char *embedded_server_groups[]=
@@ -197,6 +240,10 @@ static ulonglong timer_now(void);
static ulong connection_retry_sleep= 100000; /* Microseconds */
+static const char *opt_plugin_dir;
+static const char *opt_suite_dir, *opt_overlay_dir;
+static size_t suite_dir_len, overlay_dir_len;
+
/* Precompiled re's */
static my_regex_t ps_re; /* the query can be run using PS protocol */
static my_regex_t sp_re; /* the query can be run as a SP */
@@ -238,8 +285,9 @@ typedef struct
int str_val_len;
int int_val;
int alloced_len;
- int int_dirty; /* do not update string if int is updated until first read */
- int alloced;
+ bool int_dirty; /* do not update string if int is updated until first read */
+ bool is_int;
+ bool alloced;
} VAR;
/*Perl/shell-like variable registers */
@@ -259,13 +307,16 @@ struct st_connection
my_bool pending;
#ifdef EMBEDDED_LIBRARY
+ pthread_t tid;
const char *cur_query;
int cur_query_len;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- pthread_t tid;
+ int command, result;
+ pthread_mutex_t query_mutex;
+ pthread_cond_t query_cond;
+ pthread_mutex_t result_mutex;
+ pthread_cond_t result_cond;
int query_done;
- my_bool has_thread, mutex_inited;
+ my_bool has_thread;
#endif /*EMBEDDED_LIBRARY*/
};
@@ -292,8 +343,7 @@ enum enum_commands {
Q_SEND, Q_REAP,
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
Q_PING, Q_EVAL,
- Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
- Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
+ Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
Q_ENABLE_CONNECT_LOG, Q_DISABLE_CONNECT_LOG,
@@ -309,6 +359,7 @@ enum enum_commands {
Q_LOWERCASE,
Q_START_TIMER, Q_END_TIMER,
Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
+ Q_ENABLE_NON_BLOCKING_API, Q_DISABLE_NON_BLOCKING_API,
Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
Q_IF,
Q_DISABLE_PARSING, Q_ENABLE_PARSING,
@@ -318,12 +369,13 @@ enum enum_commands {
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
+ Q_RESULT_FORMAT_VERSION,
Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL,
Q_ENABLE_PREPARE_WARNINGS, Q_DISABLE_PREPARE_WARNINGS,
-
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
- Q_COMMENT_WITH_COMMAND
+ Q_COMMENT_WITH_COMMAND,
+ Q_EMPTY_LINE
};
@@ -356,9 +408,6 @@ const char *command_names[]=
"replace_column",
"ping",
"eval",
- "rpl_probe",
- "enable_rpl_parse",
- "disable_rpl_parse",
"eval_result",
/* Enable/disable that the _query_ is logged to result file */
"enable_query_log",
@@ -392,6 +441,8 @@ const char *command_names[]=
"character_set",
"disable_ps_protocol",
"enable_ps_protocol",
+ "enable_non_blocking_api",
+ "disable_non_blocking_api",
"disable_reconnect",
"enable_reconnect",
"if",
@@ -421,6 +472,7 @@ const char *command_names[]=
"list_files_append_file",
"send_shutdown",
"shutdown_server",
+ "result_format",
"move_file",
"remove_files_wildcard",
"send_eval",
@@ -477,28 +529,56 @@ TYPELIB command_typelib= {array_elements(command_names),"",
command_names, 0};
DYNAMIC_STRING ds_res;
+/* Points to ds_warning in run_query, so it can be freed */
+DYNAMIC_STRING *ds_warn= 0;
struct st_command *curr_command= 0;
char builtin_echo[FN_REFLEN];
+struct st_replace_regex
+{
+DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
+
+/*
+Temporary storage areas for substitutions. To reduce unnessary copying
+and memory freeing/allocation, we pre-allocate two buffers, and alternate
+their use, one for input/one for output, the roles changing on the next
+st_regex substition. At the end of substitutions buf points to the
+one containing the final result.
+*/
+char* buf;
+char* even_buf;
+char* odd_buf;
+int even_buf_len;
+int odd_buf_len;
+};
+
+struct st_replace_regex *glob_replace_regex= 0;
+
+struct st_replace;
+struct st_replace *glob_replace= 0;
+void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds,
+const char *from, int len);
+
static void cleanup_and_exit(int exit_code) __attribute__((noreturn));
-void die(const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn));
-void abort_not_supported_test(const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn));
-void verbose_msg(const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2);
-void log_msg(const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2);
+void really_die(const char *msg) __attribute__((noreturn));
+void report_or_die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+void die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2)
+ __attribute__((noreturn));
+static void make_error_message(char *buf, size_t len, const char *fmt, va_list args);
+void abort_not_supported_test(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2)
+ __attribute__((noreturn));
+void verbose_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+void log_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
VAR* var_from_env(const char *, const char *);
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
int val_len);
-void var_free(void* v);
VAR* var_get(const char *var_name, const char** var_name_end,
my_bool raw, my_bool ignore_not_existing);
-void eval_expr(VAR* v, const char *p, const char** p_end, bool do_eval= true);
+void eval_expr(VAR* v, const char *p, const char** p_end,
+ bool open_end=false, bool do_eval=true);
my_bool match_delimiter(int c, const char *delim, uint length);
void dump_result_to_reject_file(char *buf, int size);
void dump_warning_messages();
@@ -509,6 +589,8 @@ void str_to_file(const char *fname, char *str, int size);
void str_to_file2(const char *fname, char *str, int size, my_bool append);
void fix_win_paths(const char *val, int len);
+const char *get_errname_from_code (uint error_code);
+int multi_reg_replace(struct st_replace_regex* r,char* val);
#ifdef __WIN__
void free_tmp_sh_file();
@@ -559,8 +641,7 @@ public:
void open(const char* dir, const char* name, const char* ext)
{
DBUG_ENTER("LogFile::open");
- DBUG_PRINT("enter", ("dir: '%s', name: '%s'",
- val_or_null(dir), val_or_null(name)));
+ DBUG_PRINT("enter", ("dir: '%s', name: '%s'", dir, name));
if (!name)
{
m_file= stdout;
@@ -655,9 +736,8 @@ public:
DBUG_VOID_RETURN;
}
- IF_DBUG(buf[bytes]= '\0';)
- DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s",
- (unsigned long)bytes, buf));
+ DBUG_PRINT("info", ("Read %zu bytes from file, buf: %.*s",
+ bytes, (int)bytes, buf));
char* show_from= buf + bytes;
while(show_from > buf && lines > 0 )
@@ -720,14 +800,6 @@ public:
LogFile log_file;
LogFile progress_file;
-
-/* Disable functions that only exist in MySQL 4.0 */
-#if MYSQL_VERSION_ID < 40000
-void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
-void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
-int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
-my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
-#endif
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
int len);
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
@@ -742,12 +814,17 @@ void handle_error(struct st_command*,
unsigned int err_errno, const char *err_error,
const char *err_sqlstate, DYNAMIC_STRING *ds);
void handle_no_error(struct st_command*);
+void revert_properties();
static void handle_no_active_connection(struct st_command* command,
struct st_connection *cn, DYNAMIC_STRING *ds);
#ifdef EMBEDDED_LIBRARY
+#define EMB_SEND_QUERY 1
+#define EMB_READ_QUERY_RESULT 2
+#define EMB_END_CONNECTION 3
+
/* workaround for MySQL BUG#57491 */
#undef MY_WME
#define MY_WME 0
@@ -755,90 +832,140 @@ static void handle_no_active_connection(struct st_command* command,
/* attributes of the query thread */
pthread_attr_t cn_thd_attrib;
+
/*
- send_one_query executes query in separate thread, which is
- necessary in embedded library to run 'send' in proper way.
- This implementation doesn't handle errors returned
- by mysql_send_query. It's technically possible, though
- I don't see where it is needed.
+ This procedure represents the connection and actually
+ runs queries when in the EMBEDDED-SERVER mode.
+ The run_query_normal() just sends request for running
+ mysql_send_query and mysql_read_query_result() here.
*/
-pthread_handler_t send_one_query(void *arg)
+
+pthread_handler_t connection_thread(void *arg)
{
struct st_connection *cn= (struct st_connection*)arg;
- if (!cn->mysql)
- return 0;
-
mysql_thread_init();
- VOID(mysql_send_query(cn->mysql, cn->cur_query, cn->cur_query_len));
+ while (cn->command != EMB_END_CONNECTION)
+ {
+ if (!cn->command)
+ {
+ pthread_mutex_lock(&cn->query_mutex);
+ while (!cn->command)
+ pthread_cond_wait(&cn->query_cond, &cn->query_mutex);
+ pthread_mutex_unlock(&cn->query_mutex);
+ }
+ switch (cn->command)
+ {
+ case EMB_END_CONNECTION:
+ goto end_thread;
+ case EMB_SEND_QUERY:
+ cn->result= mysql_send_query(cn->mysql, cn->cur_query, cn->cur_query_len);
+ break;
+ case EMB_READ_QUERY_RESULT:
+ cn->result= mysql_read_query_result(cn->mysql);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ cn->command= 0;
+ pthread_mutex_lock(&cn->result_mutex);
+ cn->query_done= 1;
+ pthread_cond_signal(&cn->result_cond);
+ pthread_mutex_unlock(&cn->result_mutex);
+ }
- mysql_thread_end();
- pthread_mutex_lock(&cn->mutex);
+end_thread:
cn->query_done= 1;
- VOID(pthread_cond_signal(&cn->cond));
- pthread_mutex_unlock(&cn->mutex);
+ mysql_thread_end();
pthread_exit(0);
return 0;
}
-static int do_send_query(struct st_connection *cn, const char *q, int q_len,
- int flags)
+static void wait_query_thread_done(struct st_connection *con)
{
- if (!cn->mysql)
- die("Trying to send a query without a connection");
+ DBUG_ASSERT(con->has_thread);
+ if (!con->query_done)
+ {
+ pthread_mutex_lock(&con->result_mutex);
+ while (!con->query_done)
+ pthread_cond_wait(&con->result_cond, &con->result_mutex);
+ pthread_mutex_unlock(&con->result_mutex);
+ }
+}
- if (flags & QUERY_REAP_FLAG)
- return mysql_send_query(cn->mysql, q, q_len);
- if (!cn->mutex_inited &&
- (pthread_mutex_init(&cn->mutex, NULL) ||
- pthread_cond_init(&cn->cond, NULL)))
- die("Error in the thread library");
+static void signal_connection_thd(struct st_connection *cn, int command)
+{
+ DBUG_ASSERT(cn->has_thread);
+ cn->query_done= 0;
+ cn->command= command;
+ pthread_mutex_lock(&cn->query_mutex);
+ pthread_cond_signal(&cn->query_cond);
+ pthread_mutex_unlock(&cn->query_mutex);
+}
- cn->mutex_inited= 1;
+
+/*
+ Sometimes we try to execute queries when the connection is closed.
+ It's done to make sure it was closed completely.
+ So that if our connection is closed (cn->has_thread == 0), we just return
+ the mysql_send_query() result which is an error in this case.
+*/
+
+static int do_send_query(struct st_connection *cn, const char *q, int q_len)
+{
+ if (!cn->has_thread)
+ return mysql_send_query(cn->mysql, q, q_len);
cn->cur_query= q;
cn->cur_query_len= q_len;
- cn->query_done= 0;
- if (pthread_create(&cn->tid, &cn_thd_attrib, send_one_query, (void*)cn))
- die("Cannot start new thread for query");
-
- cn->has_thread= TRUE;
+ signal_connection_thd(cn, EMB_SEND_QUERY);
return 0;
}
-static void wait_query_thread_end(struct st_connection *con)
+static int do_read_query_result(struct st_connection *cn)
{
- if (!con->query_done)
- {
- pthread_mutex_lock(&con->mutex);
- while (!con->query_done)
- pthread_cond_wait(&con->cond, &con->mutex);
- pthread_mutex_unlock(&con->mutex);
- }
- if (con->has_thread)
- {
-#ifndef __WIN__
- /* May hang on Windows, but the problem it solves is not seen there */
- pthread_join(con->tid, NULL);
-#endif
- con->has_thread= FALSE;
- }
+ DBUG_ASSERT(cn->has_thread);
+ wait_query_thread_done(cn);
+ signal_connection_thd(cn, EMB_READ_QUERY_RESULT);
+ wait_query_thread_done(cn);
+
+ return cn->result;
}
-static void free_embedded_data(struct st_connection *con)
+
+static void emb_close_connection(struct st_connection *cn)
{
- if (con->mutex_inited)
- {
- con->mutex_inited= 0;
- pthread_mutex_destroy(&con->mutex);
- pthread_cond_destroy(&con->cond);
- }
+ if (!cn->has_thread)
+ return;
+ wait_query_thread_done(cn);
+ signal_connection_thd(cn, EMB_END_CONNECTION);
+ pthread_join(cn->tid, NULL);
+ cn->has_thread= FALSE;
+ pthread_mutex_destroy(&cn->query_mutex);
+ pthread_cond_destroy(&cn->query_cond);
+ pthread_mutex_destroy(&cn->result_mutex);
+ pthread_cond_destroy(&cn->result_cond);
+}
+
+
+static void init_connection_thd(struct st_connection *cn)
+{
+ cn->query_done= 1;
+ cn->command= 0;
+ if (pthread_mutex_init(&cn->query_mutex, NULL) ||
+ pthread_cond_init(&cn->query_cond, NULL) ||
+ pthread_mutex_init(&cn->result_mutex, NULL) ||
+ pthread_cond_init(&cn->result_cond, NULL) ||
+ pthread_create(&cn->tid, &cn_thd_attrib, connection_thread, (void*)cn))
+ die("Error in the thread library");
+ cn->has_thread=TRUE;
}
#else /*EMBEDDED_LIBRARY*/
-#define do_send_query(cn,q,q_len,flags) mysql_send_query(cn->mysql, q, q_len)
-#define free_embedded_data(next_con) do { } while(0)
+#define init_connection_thd(X) do { } while(0)
+#define do_send_query(cn,q,q_len) mysql_send_query(cn->mysql, q, q_len)
+#define do_read_query_result(cn) mysql_read_query_result(cn->mysql)
#endif /*EMBEDDED_LIBRARY*/
@@ -863,7 +990,10 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query,
else
{
if (!(v= var_get(p, &p, 0, 0)))
- die("Bad variable in eval");
+ {
+ report_or_die( "Bad variable in eval");
+ return;
+ }
dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
}
break;
@@ -1150,9 +1280,13 @@ void handle_command_error(struct st_command *command, uint error,
int i;
if (command->abort_on_error)
- die("command \"%.*s\" failed with error: %u my_errno: %d errno: %d",
+ {
+ report_or_die("command \"%.*s\" failed with error: %u my_errno: %d "
+ "errno: %d",
command->first_word_len, command->query, error, my_errno,
sys_errno);
+ return;
+ }
i= match_expected_error(command, error, NULL);
@@ -1161,20 +1295,25 @@ void handle_command_error(struct st_command *command, uint error,
DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d",
command->first_word_len, command->query, error,
sys_errno));
+ revert_properties();
DBUG_VOID_RETURN;
}
if (command->expected_errors.count > 0)
- die("command \"%.*s\" failed with wrong error: %u my_errno: %d errno: %d",
- command->first_word_len, command->query, error, my_errno, sys_errno);
+ report_or_die("command \"%.*s\" failed with wrong error: %u "
+ "my_errno: %d errno: %d",
+ command->first_word_len, command->query, error, my_errno,
+ sys_errno);
}
else if (command->expected_errors.err[0].type == ERR_ERRNO &&
command->expected_errors.err[0].code.errnum != 0)
{
/* Error code we wanted was != 0, i.e. not an expected success */
- die("command \"%.*s\" succeeded - should have failed with errno %d...",
+ report_or_die("command \"%.*s\" succeeded - should have failed with "
+ "errno %d...",
command->first_word_len, command->query,
command->expected_errors.err[0].code.errnum);
}
+ revert_properties();
DBUG_VOID_RETURN;
}
@@ -1184,6 +1323,9 @@ void close_connections()
DBUG_ENTER("close_connections");
for (--next_con; next_con >= connections; --next_con)
{
+#ifdef EMBEDDED_LIBRARY
+ emb_close_connection(next_con);
+#endif
if (next_con->stmt)
mysql_stmt_close(next_con->stmt);
next_con->stmt= 0;
@@ -1191,10 +1333,9 @@ void close_connections()
next_con->mysql= 0;
if (next_con->util_mysql)
mysql_close(next_con->util_mysql);
- my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
- free_embedded_data(next_con);
+ my_free(next_con->name);
}
- my_free(connections, MYF(MY_WME));
+ my_free(connections);
DBUG_VOID_RETURN;
}
@@ -1223,7 +1364,7 @@ void close_files()
DBUG_PRINT("info", ("closing file: %s", cur_file->file_name));
fclose(cur_file->file);
}
- my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(cur_file->file_name);
cur_file->file_name= 0;
}
DBUG_VOID_RETURN;
@@ -1238,27 +1379,29 @@ void free_used_memory()
if (connections)
close_connections();
close_files();
- hash_free(&var_hash);
+ my_hash_free(&var_hash);
for (i= 0 ; i < q_lines.elements ; i++)
{
struct st_command **q= dynamic_element(&q_lines, i, struct st_command**);
- my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((*q)->query_buf);
if ((*q)->content.str)
dynstr_free(&(*q)->content);
- my_free((*q),MYF(0));
+ my_free((*q));
}
for (i= 0; i < 10; i++)
{
if (var_reg[i].alloced_len)
- my_free(var_reg[i].str_val, MYF(MY_WME));
+ my_free(var_reg[i].str_val);
}
while (embedded_server_arg_count > 1)
- my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
+ my_free(embedded_server_args[--embedded_server_arg_count]);
delete_dynamic(&q_lines);
dynstr_free(&ds_res);
+ if (ds_warn)
+ dynstr_free(ds_warn);
free_all_replace();
- my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_pass);
free_defaults(default_argv);
free_root(&require_file_root, MYF(0));
free_re();
@@ -1277,6 +1420,17 @@ static void cleanup_and_exit(int exit_code)
/* Only call mysql_server_end if mysql_server_init has been called */
if (server_initialized)
mysql_server_end();
+
+ /*
+ mysqltest is fundamentally written in a way that makes impossible
+ to free all memory before exit (consider memory allocated
+ for frame local DYNAMIC_STRING's and die() invoked down the stack.
+
+ We close stderr here to stop unavoidable safemalloc reports
+ from polluting the output.
+ */
+ fclose(stderr);
+
my_end(my_end_arg);
if (!silent) {
@@ -1296,52 +1450,63 @@ static void cleanup_and_exit(int exit_code)
}
}
+ sf_leaking_memory= 0; /* all memory should be freed by now */
exit(exit_code);
}
-void print_file_stack()
+size_t print_file_stack(char *s, const char *end)
{
+ char *start= s;
struct st_test_file* err_file= cur_file;
if (err_file == file_stack)
- return;
+ return 0;
for (;;)
{
err_file--;
- fprintf(stderr, "included from %s at line %d:\n",
- err_file->file_name, err_file->lineno);
+ s+= my_snprintf(s, end - s, "included from %s at line %d:\n",
+ err_file->file_name, err_file->lineno);
if (err_file == file_stack)
break;
}
+ return s - start;
}
-void die(const char *fmt, ...)
-{
- static int dying= 0;
- va_list args;
- DBUG_ENTER("die");
- DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
- fflush(stdout);
- /* Print the error message */
- fprintf(stderr, "mysqltest: ");
+static void make_error_message(char *buf, size_t len, const char *fmt, va_list args)
+{
+ char *s= buf, *end= buf + len;
+ s+= my_snprintf(s, end - s, "mysqltest: ");
if (cur_file && cur_file != file_stack)
{
- fprintf(stderr, "In included file \"%s\": \n",
- cur_file->file_name);
- print_file_stack();
+ s+= my_snprintf(s, end - s, "In included file \"%s\": \n",
+ cur_file->file_name);
+ s+= print_file_stack(s, end);
}
+
if (start_lineno > 0)
- fprintf(stderr, "At line %u: ", start_lineno);
- if (fmt)
- {
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- }
- else
- fprintf(stderr, "unknown error");
- fprintf(stderr, "\n");
+ s+= my_snprintf(s, end -s, "At line %u: ", start_lineno);
+ if (!fmt)
+ fmt= "unknown error";
+
+ s+= my_vsnprintf(s, end - s, fmt, args);
+ s+= my_snprintf(s, end -s, "\n", start_lineno);
+}
+
+void die(const char *fmt, ...)
+{
+ char buff[DIE_BUFF_SIZE];
+ va_list args;
+ va_start(args, fmt);
+ make_error_message(buff, sizeof(buff), fmt, args);
+ really_die(buff);
+}
+
+void really_die(const char *msg)
+{
+ static int dying= 0;
+ fflush(stdout);
+ fprintf(stderr, "%s", msg);
fflush(stderr);
/*
@@ -1365,6 +1530,28 @@ void die(const char *fmt, ...)
cleanup_and_exit(1);
}
+void report_or_die(const char *fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("report_or_die");
+
+ char buff[DIE_BUFF_SIZE];
+
+ va_start(args, fmt);
+ make_error_message(buff, sizeof(buff), fmt, args);
+ va_end(args);
+
+ if (opt_continue_on_error)
+ {
+ /* Just log the error and continue */
+ replace_dynstr_append(&ds_res, buff);
+ error_count++;
+ DBUG_VOID_RETURN;
+ }
+
+ really_die(buff);
+}
+
void abort_not_supported_test(const char *fmt, ...)
{
@@ -1377,7 +1564,10 @@ void abort_not_supported_test(const char *fmt, ...)
file_stack->file_name);
fprintf(stderr, "Detected in file %s at line %d\n",
cur_file->file_name, cur_file->lineno);
- print_file_stack();
+
+ char buff[DIE_BUFF_SIZE];
+ print_file_stack(buff, buff + sizeof(buff));
+ fprintf(stderr, "%s", buff);
/* Print error message */
va_start(args, fmt);
@@ -1509,7 +1699,10 @@ static int run_command(char* cmd,
DBUG_PRINT("enter", ("cmd: %s", cmd));
if (!(res_file= popen(cmd, "r")))
- die("popen(\"%s\", \"r\") failed", cmd);
+ {
+ report_or_die("popen(\"%s\", \"r\") failed", cmd);
+ return -1;
+ }
while (fgets(buf, sizeof(buf), res_file))
{
@@ -1609,7 +1802,10 @@ static int diff_check(const char *diff_name)
if (!(res_file= popen(buf, "r")))
die("popen(\"%s\", \"r\") failed", buf);
- /* if diff is not present, nothing will be in stdout to increment have_diff */
+ /*
+ if diff is not present, nothing will be in stdout to increment
+ have_diff
+ */
if (fgets(buf, sizeof(buf), res_file))
have_diff= 1;
@@ -1922,7 +2118,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
void check_result()
{
- const char* mess= "Result content mismatch\n";
+ const char *mess= 0;
DBUG_ENTER("check_result");
DBUG_ASSERT(result_file_name);
@@ -1930,9 +2126,13 @@ void check_result()
switch (compare_files(log_file.file_name(), result_file_name)) {
case RESULT_OK:
- break; /* ok */
+ if (!error_count)
+ break; /* ok */
+ mess= "Got errors while running test";
+ /* Fallthrough */
case RESULT_LENGTH_MISMATCH:
- mess= "Result length mismatch\n";
+ if (!mess)
+ mess= "Result length mismatch\n";
/* Fallthrough */
case RESULT_CONTENT_MISMATCH:
{
@@ -1942,6 +2142,10 @@ void check_result()
*/
char reject_file[FN_REFLEN];
size_t reject_length;
+
+ if (!mess)
+ mess= "Result content mismatch\n";
+
dirname_part(reject_file, result_file_name, &reject_length);
if (access(reject_file, W_OK) == 0)
@@ -2041,11 +2245,13 @@ static int strip_surrounding(char* str, char c1, char c2)
static void strip_parentheses(struct st_command *command)
{
if (strip_surrounding(command->first_argument, '(', ')'))
- die("%.*s - argument list started with '%c' must be ended with '%c'",
- command->first_word_len, command->query, '(', ')');
+ die("%.*s - argument list started with '%c' must be ended with '%c'",
+ command->first_word_len, command->query, '(', ')');
}
+C_MODE_START
+
static uchar *get_var_key(const uchar* var, size_t *len,
my_bool __attribute__((unused)) t)
{
@@ -2056,6 +2262,34 @@ static uchar *get_var_key(const uchar* var, size_t *len,
}
+static void var_free(void *v)
+{
+ VAR *var= (VAR*) v;
+ my_free(var->str_val);
+ if (var->alloced)
+ my_free(var);
+}
+
+C_MODE_END
+
+void var_check_int(VAR *v)
+{
+ char *endptr;
+ char *str= v->str_val;
+
+ /* Initially assume not a number */
+ v->int_val= 0;
+ v->is_int= false;
+ v->int_dirty= false;
+ if (!str) return;
+
+ v->int_val = (int) strtol(str, &endptr, 10);
+ /* It is an int if strtol consumed something up to end/space/tab */
+ if (endptr > str && (!*endptr || *endptr == ' ' || *endptr == '\t'))
+ v->is_int= true;
+}
+
+
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
int val_len)
{
@@ -2065,6 +2299,8 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
name_len = strlen(name);
if (!val_len && val)
val_len = strlen(val) ;
+ if (!val)
+ val_len= 0;
val_alloc_len = val_len + 16; /* room to grow */
if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
+ name_len+2, MYF(MY_WME))))
@@ -2085,27 +2321,17 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
die("Out of memory");
if (val)
- {
memcpy(tmp_var->str_val, val, val_len);
- tmp_var->str_val[val_len]= 0;
- }
+ tmp_var->str_val[val_len]= 0;
+
+ var_check_int(tmp_var);
tmp_var->name_len = name_len;
tmp_var->str_val_len = val_len;
tmp_var->alloced_len = val_alloc_len;
- tmp_var->int_val = (val) ? atoi(val) : 0;
- tmp_var->int_dirty = 0;
return tmp_var;
}
-void var_free(void *v)
-{
- my_free(((VAR*) v)->str_val, MYF(MY_WME));
- if (((VAR*)v)->alloced)
- my_free(v, MYF(MY_WME));
-}
-
-
VAR* var_from_env(const char *name, const char *def_val)
{
const char *tmp;
@@ -2147,8 +2373,8 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw,
if (length >= MAX_VAR_NAME_LENGTH)
die("Too long variable name: %s", save_var_name);
- if (!(v = (VAR*) hash_search(&var_hash, (const uchar*) save_var_name,
- length)))
+ if (!(v = (VAR*) my_hash_search(&var_hash, (const uchar*) save_var_name,
+ length)))
{
char buff[MAX_VAR_NAME_LENGTH+1];
strmake(buff, save_var_name, length);
@@ -2162,7 +2388,7 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw,
if (!raw && v->int_dirty)
{
sprintf(v->str_val, "%d", v->int_val);
- v->int_dirty = 0;
+ v->int_dirty= false;
v->str_val_len = strlen(v->str_val);
}
if (var_name_end)
@@ -2179,7 +2405,7 @@ err:
VAR *var_obtain(const char *name, int len)
{
VAR* v;
- if ((v = (VAR*)hash_search(&var_hash, (const uchar *) name, len)))
+ if ((v = (VAR*)my_hash_search(&var_hash, (const uchar *) name, len)))
return v;
v = var_init(0, name, len, "", 0);
my_hash_insert(&var_hash, (uchar*)v);
@@ -2224,7 +2450,7 @@ void var_set(const char *var_name, const char *var_name_end,
if (v->int_dirty)
{
sprintf(v->str_val, "%d", v->int_val);
- v->int_dirty= 0;
+ v->int_dirty=false;
v->str_val_len= strlen(v->str_val);
}
/* setenv() expects \0-terminated strings */
@@ -2257,6 +2483,51 @@ void var_set_int(const char* name, int value)
void var_set_errno(int sql_errno)
{
var_set_int("$mysql_errno", sql_errno);
+ var_set_string("$mysql_errname", get_errname_from_code(sql_errno));
+}
+
+/* Functions to handle --disable and --enable properties */
+
+void set_once_property(enum_prop prop, my_bool val)
+{
+ property &pr= prop_list[prop];
+ pr.set= 1;
+ pr.old= *pr.var;
+ *pr.var= val;
+ var_set_int(pr.env_name, (val != pr.reverse));
+ once_property= TRUE;
+}
+
+void set_property(st_command *command, enum_prop prop, my_bool val)
+{
+ char* p= command->first_argument;
+ if (p && !strcmp (p, "ONCE"))
+ {
+ command->last_argument= p + 4;
+ set_once_property(prop, val);
+ return;
+ }
+ property &pr= prop_list[prop];
+ *pr.var= val;
+ pr.set= 0;
+ var_set_int(pr.env_name, (val != pr.reverse));
+}
+
+void revert_properties()
+{
+ if (! once_property)
+ return;
+ for (int i= 0; i < (int) P_MAX; i++)
+ {
+ property &pr= prop_list[i];
+ if (pr.set)
+ {
+ *pr.var= pr.old;
+ pr.set= 0;
+ var_set_int(pr.env_name, (pr.old != pr.reverse));
+ }
+ }
+ once_property=FALSE;
}
@@ -2325,8 +2596,8 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
if (mysql_real_query(mysql, ds_query.str, ds_query.length))
{
- handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), &ds_res);
+ handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), &ds_res);
/* If error was acceptable, return empty string */
dynstr_free(&ds_query);
eval_expr(var, "", 0);
@@ -2334,7 +2605,12 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
}
if (!(res= mysql_store_result(mysql)))
- die("Query '%s' didn't return a result set", ds_query.str);
+ {
+ report_or_die("Query '%s' didn't return a result set", ds_query.str);
+ dynstr_free(&ds_query);
+ eval_expr(var, "", 0);
+ return;
+ }
dynstr_free(&ds_query);
if ((row= mysql_fetch_row(res)) && row[0])
@@ -2354,13 +2630,29 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
if (row[i])
{
/* Add column to tab separated string */
- dynstr_append_mem(&result, row[i], lengths[i]);
+ char *val= row[i];
+ int len= lengths[i];
+
+ if (glob_replace_regex)
+ {
+ /* Regex replace */
+ if (!multi_reg_replace(glob_replace_regex, (char*)val))
+ {
+ val= glob_replace_regex->buf;
+ len= strlen(val);
+ }
+ }
+
+ if (glob_replace)
+ replace_strings_append(glob_replace, &result, val, len);
+ else
+ dynstr_append_mem(&result, val, len);
}
dynstr_append_mem(&result, "\t", 1);
}
end= result.str + result.length-1;
/* Evaluation should not recurse via backtick */
- eval_expr(var, result.str, (const char**) &end, false);
+ eval_expr(var, result.str, (const char**) &end, false, false);
dynstr_free(&result);
}
else
@@ -2371,6 +2663,59 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
}
+static void
+set_result_format_version(ulong new_version)
+{
+ switch (new_version){
+ case 1:
+ /* The first format */
+ break;
+ case 2:
+ /* New format that also writes comments and empty lines
+ from test file to result */
+ break;
+ default:
+ die("Version format %lu has not yet been implemented", new_version);
+ break;
+ }
+ opt_result_format_version= new_version;
+}
+
+
+/*
+ Set the result format version to use when generating
+ the .result file
+*/
+
+static void
+do_result_format_version(struct st_command *command)
+{
+ long version;
+ static DYNAMIC_STRING ds_version;
+ const struct command_arg result_format_args[] = {
+ {"version", ARG_STRING, TRUE, &ds_version, "Version to use"}
+ };
+
+ DBUG_ENTER("do_result_format_version");
+
+ check_command_args(command, command->first_argument,
+ result_format_args,
+ sizeof(result_format_args)/sizeof(struct command_arg),
+ ',');
+
+ /* Convert version number to int */
+ if (!str2int(ds_version.str, 10, (long) 0, (long) INT_MAX, &version))
+ die("Invalid version number: '%s'", ds_version.str);
+
+ set_result_format_version(version);
+
+ dynstr_append(&ds_res, "result_format: ");
+ dynstr_append_mem(&ds_res, ds_version.str, ds_version.length);
+ dynstr_append(&ds_res, "\n");
+ dynstr_free(&ds_version);
+}
+
+
/*
Set variable from the result of a field in a query
@@ -2440,16 +2785,23 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
/* Run the query */
if (mysql_real_query(mysql, ds_query.str, ds_query.length))
{
- handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), &ds_res);
+ handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), &ds_res);
/* If error was acceptable, return empty string */
dynstr_free(&ds_query);
+ dynstr_free(&ds_col);
eval_expr(var, "", 0);
DBUG_VOID_RETURN;
}
if (!(res= mysql_store_result(mysql)))
- die("Query '%s' didn't return a result set", ds_query.str);
+ {
+ report_or_die("Query '%s' didn't return a result set", ds_query.str);
+ dynstr_free(&ds_query);
+ dynstr_free(&ds_col);
+ eval_expr(var, "", 0);
+ return;
+ }
{
/* Find column number from the given column name */
@@ -2469,8 +2821,11 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
if (col_no == -1)
{
mysql_free_result(res);
- die("Could not find column '%s' in the result of '%s'",
- ds_col.str, ds_query.str);
+ report_or_die("Could not find column '%s' in the result of '%s'",
+ ds_col.str, ds_query.str);
+ dynstr_free(&ds_query);
+ dynstr_free(&ds_col);
+ return;
}
DBUG_PRINT("info", ("Found column %d with name '%s'",
i, fields[i].name));
@@ -2499,7 +2854,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
break;
}
}
- eval_expr(var, value, 0, false);
+ eval_expr(var, value, 0, false, false);
}
dynstr_free(&ds_query);
mysql_free_result(res);
@@ -2511,6 +2866,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
void var_copy(VAR *dest, VAR *src)
{
dest->int_val= src->int_val;
+ dest->is_int= src->is_int;
dest->int_dirty= src->int_dirty;
/* Alloc/realloc data for str_val in dest */
@@ -2529,7 +2885,8 @@ void var_copy(VAR *dest, VAR *src)
}
-void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval)
+void eval_expr(VAR *v, const char *p, const char **p_end,
+ bool open_end, bool do_eval)
{
DBUG_ENTER("eval_expr");
@@ -2551,7 +2908,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval)
/* Make sure there was just a $variable and nothing else */
const char* end= *p_end + 1;
- if (end < expected_end)
+ if (end < expected_end && !open_end)
die("Found junk '%.*s' after $variable in expression",
(int)(expected_end - end - 1), end);
@@ -2600,48 +2957,134 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval)
v->str_val_len = new_val_len;
memcpy(v->str_val, p, new_val_len);
v->str_val[new_val_len] = 0;
- v->int_val=atoi(p);
- DBUG_PRINT("info", ("atoi on '%s', returns: %d", p, v->int_val));
- v->int_dirty=0;
+ var_check_int(v);
}
DBUG_VOID_RETURN;
}
-int open_file(const char *name)
+bool open_and_set_current(const char *name)
+{
+ FILE *opened= fopen(name, "rb");
+
+ if (!opened)
+ return false;
+
+ cur_file++;
+ cur_file->file= opened;
+ cur_file->file_name= my_strdup(name, MYF(MY_FAE));
+ cur_file->lineno=1;
+ return true;
+}
+
+
+void open_file(const char *name)
{
char buff[FN_REFLEN];
size_t length;
+ const char *curname= cur_file->file_name;
DBUG_ENTER("open_file");
DBUG_PRINT("enter", ("name: %s", name));
- /* Extract path from current file and try it as base first */
- if (dirname_part(buff, cur_file->file_name, &length))
+ if (cur_file == file_stack_end)
+ die("Source directives are nesting too deep");
+
+ if (test_if_hard_path(name))
{
- strxmov(buff, buff, name, NullS);
- if (access(buff, F_OK) == 0){
- DBUG_PRINT("info", ("The file exists"));
- name= buff;
- }
+ if (open_and_set_current(name))
+ DBUG_VOID_RETURN;
}
- if (!test_if_hard_path(name))
+ else
{
- strxmov(buff, opt_basedir, name, NullS);
- name=buff;
- }
- fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
+ /*
+ if overlay-dir is specified, and the file is located somewhere
+ under overlay-dir or under suite-dir, the search works as follows:
+
+ 0.let suffix be current file dirname relative to siute-dir or overlay-dir
+ 1.try in overlay-dir/suffix
+ 2.try in suite-dir/suffix
+ 3.try in overlay-dir
+ 4.try in suite-dir
+ 5.try in basedir
+
+ consider an example: 'rty' overlay of the 'qwe' suite,
+ file qwe/include/some.inc contains the line
+ --source thing.inc
+ we look for it in this order:
+ 0.suffix is "include/"
+ 1.try in rty/include/thing.inc
+ 2.try in qwe/include/thing.inc
+ 3.try in try/thing.inc | this is useful when t/a.test has
+ 4.try in qwe/thing.inc | source include/b.inc;
+ 5.try in mysql-test/include/thing.inc
+
+ otherwise the search is as follows
+ 1.try in current file dirname
+ 3.try in overlay-dir (if any)
+ 4.try in suite-dir
+ 5.try in basedir
+ */
- if (cur_file == file_stack_end)
- die("Source directives are nesting too deep");
- cur_file++;
- if (!(cur_file->file = fopen(buff, "rb")))
- {
- cur_file--;
- die("Could not open '%s' for reading, errno: %d", buff, errno);
+ bool in_overlay= opt_overlay_dir &&
+ !strncmp(curname, opt_overlay_dir, overlay_dir_len);
+ bool in_suiteir= opt_overlay_dir && !in_overlay &&
+ !strncmp(curname, opt_suite_dir, suite_dir_len);
+ if (in_overlay || in_suiteir)
+ {
+ size_t prefix_len = in_overlay ? overlay_dir_len : suite_dir_len;
+ char buf2[FN_REFLEN], *suffix= buf2 + prefix_len;
+ dirname_part(buf2, curname, &length);
+
+ /* 1. first we look in the overlay dir */
+ strxnmov(buff, sizeof(buff), opt_overlay_dir, suffix, name, NullS);
+
+ /*
+ Overlayed rty/include/thing.inc can contain the line
+ --source thing.inc
+ which would mean to include qwe/include/thing.inc.
+ But it looks like including "itself", so don't try to open the file,
+ if buff contains the same file name as curname.
+ */
+ if (strcmp(buff, curname) && open_and_set_current(buff))
+ DBUG_VOID_RETURN;
+
+ /* 2. if that failed, we look in the suite dir */
+ strxnmov(buff, sizeof(buff), opt_suite_dir, suffix, name, NullS);
+
+ /* buff can not be equal to curname, as a file can never include itself */
+ if (open_and_set_current(buff))
+ DBUG_VOID_RETURN;
+ }
+ else
+ {
+ /* 1. try in current file dirname */
+ dirname_part(buff, curname, &length);
+ strxnmov(buff, sizeof(buff), buff, name, NullS);
+ if (open_and_set_current(buff))
+ DBUG_VOID_RETURN;
+ }
+
+ /* 3. now, look in the overlay dir */
+ if (opt_overlay_dir)
+ {
+ strxmov(buff, opt_overlay_dir, name, NullS);
+ if (open_and_set_current(buff))
+ DBUG_VOID_RETURN;
+ }
+
+ /* 4. if that failed - look in the suite dir */
+ strxmov(buff, opt_suite_dir, name, NullS);
+ if (open_and_set_current(buff))
+ DBUG_VOID_RETURN;
+
+ /* 5. the last resort - look in the base dir */
+ strxnmov(buff, sizeof(buff), opt_basedir, name, NullS);
+ if (open_and_set_current(buff))
+ DBUG_VOID_RETURN;
}
- cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
- cur_file->lineno=1;
- DBUG_RETURN(0);
+
+ die("Could not open '%s' for reading, errno: %d", name, errno);
+ DBUG_VOID_RETURN;
}
@@ -2822,7 +3265,10 @@ void do_exec(struct st_command *command)
while (*cmd && my_isspace(charset_info, *cmd))
cmd++;
if (!*cmd)
- die("Missing argument in exec");
+ {
+ report_or_die("Missing argument in exec");
+ return;
+ }
command->last_argument= command->end;
init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256);
@@ -2854,10 +3300,12 @@ void do_exec(struct st_command *command)
DBUG_PRINT("info", ("Executing '%s' as '%s'",
command->first_argument, ds_cmd.str));
- if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error)
+ if (!(res_file= my_popen(&ds_cmd, "r")))
{
dynstr_free(&ds_cmd);
- die("popen(\"%s\", \"r\") failed", command->first_argument);
+ if (command->abort_on_error)
+ report_or_die("popen(\"%s\", \"r\") failed", command->first_argument);
+ return;
}
ds_result= &ds_res;
@@ -2894,11 +3342,12 @@ void do_exec(struct st_command *command)
if (command->abort_on_error)
{
- log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d",
- ds_cmd.str, error, status, errno);
+ report_or_die("exec of '%s' failed, error: %d, status: %d, errno: %d\n"
+ "Output from before failure:\n%s\n",
+ ds_cmd.str, error, status, errno,
+ ds_res.str);
dynstr_free(&ds_cmd);
- die("command \"%s\" failed\n\nOutput from before failure:\n%s\n",
- command->first_argument, ds_res.str);
+ return;
}
DBUG_PRINT("info",
@@ -2913,8 +3362,8 @@ void do_exec(struct st_command *command)
{
dynstr_free(&ds_cmd);
if (command->expected_errors.count > 0)
- die("command \"%s\" failed with wrong error: %d",
- command->first_argument, status);
+ report_or_die("command \"%s\" failed with wrong error: %d",
+ command->first_argument, status);
}
}
else if (command->expected_errors.err[0].type == ERR_ERRNO &&
@@ -2924,8 +3373,10 @@ void do_exec(struct st_command *command)
log_msg("exec of '%s failed, error: %d, errno: %d",
ds_cmd.str, error, errno);
dynstr_free(&ds_cmd);
- die("command \"%s\" succeeded - should have failed with errno %d...",
- command->first_argument, command->expected_errors.err[0].code.errnum);
+ report_or_die("command \"%s\" succeeded - should have failed with "
+ "errno %d...",
+ command->first_argument,
+ command->expected_errors.err[0].code.errnum);
}
dynstr_free(&ds_cmd);
@@ -2959,11 +3410,14 @@ int do_modify_var(struct st_command *command,
const char *p= command->first_argument;
VAR* v;
if (!*p)
- die("Missing argument to %.*s", command->first_word_len, command->query);
+ die("Missing argument to %.*s", command->first_word_len,
+ command->query);
if (*p != '$')
die("The argument to %.*s must be a variable (start with $)",
command->first_word_len, command->query);
v= var_get(p, &p, 1, 0);
+ if (! v->is_int)
+ die("Cannot perform inc/dec on a non-numeric value");
switch (op) {
case DO_DEC:
v->int_val--;
@@ -2975,7 +3429,7 @@ int do_modify_var(struct st_command *command,
die("Invalid operator to do_modify_var");
break;
}
- v->int_dirty= 1;
+ v->int_dirty= true;
command->last_argument= (char*)++p;
return 0;
}
@@ -3023,7 +3477,10 @@ void do_system(struct st_command *command)
DBUG_ENTER("do_system");
if (strlen(command->first_argument) == 0)
- die("Missing arguments to system, nothing to do!");
+ {
+ report_or_die("Missing arguments to system, nothing to do!");
+ return;
+ }
init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256);
@@ -3044,12 +3501,14 @@ void do_system(struct st_command *command)
if (my_system(&ds_cmd))
{
if (command->abort_on_error)
- die("system command '%s' failed", command->first_argument);
-
- /* If ! abort_on_error, log message and continue */
- dynstr_append(&ds_res, "system command '");
- replace_dynstr_append(&ds_res, command->first_argument);
- dynstr_append(&ds_res, "' failed\n");
+ report_or_die("system command '%s' failed", command->first_argument);
+ else
+ {
+ /* If ! abort_on_error, log message and continue */
+ dynstr_append(&ds_res, "system command '");
+ replace_dynstr_append(&ds_res, command->first_argument);
+ dynstr_append(&ds_res, "' failed\n");
+ }
}
command->last_argument= command->end;
@@ -3235,8 +3694,9 @@ void do_copy_file(struct st_command *command)
' ');
DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str));
+ /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */
error= (my_copy(ds_from_file.str, ds_to_file.str,
- MYF(MY_DONT_OVERWRITE_FILE | MY_WME)) != 0);
+ MYF(MY_DONT_OVERWRITE_FILE | MY_WME | MY_HOLD_ORIGINAL_MODES)) != 0);
handle_command_error(command, error, my_errno);
dynstr_free(&ds_from_file);
dynstr_free(&ds_to_file);
@@ -3293,8 +3753,8 @@ void do_move_file(struct st_command *command)
void do_chmod_file(struct st_command *command)
{
- int error;
long mode= 0;
+ int err_code;
static DYNAMIC_STRING ds_mode;
static DYNAMIC_STRING ds_file;
const struct command_arg chmod_file_args[] = {
@@ -3314,10 +3774,10 @@ void do_chmod_file(struct st_command *command)
die("You must write a 4 digit octal number for mode");
DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str));
- error= 0;
- if (chmod(ds_file.str, mode))
- error= 1;
- handle_command_error(command, error, errno);
+ err_code= chmod(ds_file.str, mode);
+ if (err_code < 0)
+ err_code= 1;
+ handle_command_error(command, err_code, errno);
dynstr_free(&ds_mode);
dynstr_free(&ds_file);
DBUG_VOID_RETURN;
@@ -3595,12 +4055,12 @@ void read_until_delimiter(DYNAMIC_STRING *ds,
No characters except \n are allowed on
the same line as the command
*/
- die("Trailing characters found after command");
+ report_or_die("Trailing characters found after command");
}
if (feof(cur_file->file))
- die("End of file encountered before '%s' delimiter was found",
- ds_delimiter->str);
+ report_or_die("End of file encountered before '%s' delimiter was found",
+ ds_delimiter->str);
if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length))
{
@@ -4004,8 +4464,13 @@ void do_perl(struct st_command *command)
/* Format the "perl <filename>" command */
my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path);
- if (!(res_file= popen(buf, "r")) && command->abort_on_error)
- die("popen(\"%s\", \"r\") failed", buf);
+ if (!(res_file= popen(buf, "r")))
+ {
+ if (command->abort_on_error)
+ die("popen(\"%s\", \"r\") failed", buf);
+ dynstr_free(&ds_delimiter);
+ return;
+ }
while (fgets(buf, sizeof(buf), res_file))
{
@@ -4036,7 +4501,7 @@ void do_perl(struct st_command *command)
abort_not_supported_test("perl not found in path");
#endif
else
- handle_command_error(command, WEXITSTATUS(error), my_errno);
+ handle_command_error(command, exstat, my_errno);
}
dynstr_free(&ds_delimiter);
DBUG_VOID_RETURN;
@@ -4160,14 +4625,14 @@ void do_sync_with_master2(struct st_command *command, long offset)
information is not initialized, the arguments are
incorrect, or an error has occured
*/
- die("%.*s failed: '%s' returned NULL "\
+ die("%.*s failed: '%s' returned NULL " \
"indicating slave SQL thread failure",
command->first_word_len, command->query, query_buf);
}
if (result == -1)
- die("%.*s failed: '%s' returned -1 "\
+ die("%.*s failed: '%s' returned -1 " \
"indicating timeout after %d seconds",
command->first_word_len, command->query, query_buf, timeout);
else
@@ -4207,12 +4672,8 @@ int do_save_master_pos()
MYSQL_ROW row;
MYSQL *mysql = cur_con->mysql;
const char *query;
- int rpl_parse;
DBUG_ENTER("do_save_master_pos");
- rpl_parse = mysql_rpl_parse_enabled(mysql);
- mysql_disable_rpl_parse(mysql);
-
#ifdef HAVE_NDB_BINLOG
/*
Wait for ndb binlog to be up-to-date with all changes
@@ -4253,7 +4714,7 @@ int do_save_master_pos()
const char latest_applied_binlog_epoch_str[]=
"latest_applied_binlog_epoch=";
if (count)
- sleep(1);
+ my_sleep(100*1000); /* 100ms */
if (mysql_query(mysql, query= "show engine ndb status"))
die("failed in '%s': %d %s", query,
mysql_errno(mysql), mysql_error(mysql));
@@ -4342,7 +4803,7 @@ int do_save_master_pos()
count++;
if (latest_handled_binlog_epoch >= start_epoch)
do_continue= 0;
- else if (count > 30)
+ else if (count > 300) /* 30s */
{
break;
}
@@ -4362,10 +4823,6 @@ int do_save_master_pos()
strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
master_pos.pos = strtoul(row[1], (char**) 0, 10);
mysql_free_result(res);
-
- if (rpl_parse)
- mysql_enable_rpl_parse(mysql);
-
DBUG_RETURN(0);
}
@@ -4424,33 +4881,11 @@ void do_let(struct st_command *command)
var_set(var_name, var_name_end, let_rhs_expr.str,
(let_rhs_expr.str + let_rhs_expr.length));
dynstr_free(&let_rhs_expr);
+ revert_properties();
DBUG_VOID_RETURN;
}
-int do_rpl_probe(struct st_command *command __attribute__((unused)))
-{
- DBUG_ENTER("do_rpl_probe");
- if (mysql_rpl_probe(cur_con->mysql))
- die("Failed in mysql_rpl_probe(): '%s'", mysql_error(cur_con->mysql));
- DBUG_RETURN(0);
-}
-
-
-int do_enable_rpl_parse(struct st_command *command __attribute__((unused)))
-{
- mysql_enable_rpl_parse(cur_con->mysql);
- return 0;
-}
-
-
-int do_disable_rpl_parse(struct st_command *command __attribute__((unused)))
-{
- mysql_disable_rpl_parse(cur_con->mysql);
- return 0;
-}
-
-
/*
Sleep the number of specified seconds
@@ -4492,7 +4927,8 @@ int do_sleep(struct st_command *command, my_bool real_sleep)
while (my_isspace(charset_info, *p))
p++;
if (!*p)
- die("Missing argument to %.*s", command->first_word_len, command->query);
+ die("Missing argument to %.*s", command->first_word_len,
+ command->query);
sleep_start= p;
/* Check that arg starts with a digit, not handled by my_strtod */
if (!my_isdigit(charset_info, *sleep_start))
@@ -4564,16 +5000,21 @@ int query_get_string(MYSQL* mysql, const char* query,
MYSQL_ROW row;
if (mysql_query(mysql, query))
- die("'%s' failed: %d %s", query,
- mysql_errno(mysql), mysql_error(mysql));
+ {
+ report_or_die("'%s' failed: %d %s", query,
+ mysql_errno(mysql), mysql_error(mysql));
+ return 1;
+ }
if ((res= mysql_store_result(mysql)) == NULL)
- die("Failed to store result: %d %s",
- mysql_errno(mysql), mysql_error(mysql));
+ {
+ report_or_die("Failed to store result: %d %s",
+ mysql_errno(mysql), mysql_error(mysql));
+ return 1;
+ }
if ((row= mysql_fetch_row(res)) == NULL)
{
mysql_free_result(res);
- ds= 0;
return 1;
}
init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32);
@@ -4693,18 +5134,19 @@ void do_shutdown_server(struct st_command *command)
}
-#if MYSQL_VERSION_ID >= 50000
-/* List of error names to error codes, available from 5.0 */
+/* List of error names to error codes */
typedef struct
{
const char *name;
uint code;
+ const char *text;
} st_error;
static st_error global_error_names[] =
{
+ { "<No error>", -1, "" },
#include <mysqld_ername.h>
- { 0, 0 }
+ { 0, 0, 0 }
};
uint get_errcode_from_name(char *error_name, char *error_end)
@@ -4733,22 +5175,35 @@ uint get_errcode_from_name(char *error_name, char *error_end)
die("Unknown SQL error name '%s'", error_name);
DBUG_RETURN(0);
}
-#else
-uint get_errcode_from_name(char *error_name __attribute__((unused)),
- char *error_end __attribute__((unused)))
+
+const char *get_errname_from_code (uint error_code)
{
- abort_not_in_this_version();
- return 0; /* Never reached */
-}
-#endif
+ st_error *e= global_error_names;
+ DBUG_ENTER("get_errname_from_code");
+ DBUG_PRINT("enter", ("error_code: %d", error_code));
+ if (! error_code)
+ {
+ DBUG_RETURN("");
+ }
+ for (; e->name; e++)
+ {
+ if (e->code == error_code)
+ {
+ DBUG_RETURN(e->name);
+ }
+ }
+ /* Apparently, errors without known names may occur */
+ DBUG_RETURN("<Unknown>");
+}
void do_get_errcodes(struct st_command *command)
{
struct st_match_err *to= saved_expected_errors.err;
char *p= command->first_argument;
uint count= 0;
+ char *next;
DBUG_ENTER("do_get_errcodes");
@@ -4768,6 +5223,17 @@ void do_get_errcodes(struct st_command *command)
while (*end && *end != ',' && *end != ' ')
end++;
+ next=end;
+
+ /* code to handle variables passed to mysqltest */
+ if( *p == '$')
+ {
+ const char* fin;
+ VAR *var = var_get(p,&fin,0,0);
+ p=var->str_val;
+ end=p+var->str_val_len;
+ }
+
if (*p == 'S')
{
char *to_ptr= to->code.sqlstate;
@@ -4820,7 +5286,7 @@ void do_get_errcodes(struct st_command *command)
while (*p && p != end)
{
if (!my_isdigit(charset_info, *p))
- die("Invalid argument to error: '%s' - "\
+ die("Invalid argument to error: '%s' - " \
"the errno may only consist of digits[0-9]",
command->first_argument);
p++;
@@ -4842,7 +5308,7 @@ void do_get_errcodes(struct st_command *command)
die("Too many errorcodes specified");
/* Set pointer to the end of the last error code */
- p= end;
+ p= next;
/* Find next ',' */
while (*p && *p != ',')
@@ -5050,7 +5516,7 @@ void do_close_connection(struct st_command *command)
we need to check if the query's thread was finished and probably wait
(embedded-server specific)
*/
- wait_query_thread_end(con);
+ emb_close_connection(con);
#endif /*EMBEDDED_LIBRARY*/
if (con->stmt)
mysql_stmt_close(con->stmt);
@@ -5058,14 +5524,13 @@ void do_close_connection(struct st_command *command)
mysql_close(con->mysql);
con->mysql= 0;
- free_embedded_data(con);
if (con->util_mysql)
mysql_close(con->util_mysql);
con->util_mysql= 0;
con->pending= FALSE;
- my_free(con->name, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(con->name);
/*
When the connection is closed set name to "-closed_connection-"
@@ -5276,6 +5741,7 @@ do_handle_error:
var_set_errno(0);
handle_no_error(command);
+ revert_properties();
return 1; /* Connected */
}
@@ -5324,6 +5790,7 @@ void do_connect(struct st_command *command)
static DYNAMIC_STRING ds_port;
static DYNAMIC_STRING ds_sock;
static DYNAMIC_STRING ds_options;
+ static DYNAMIC_STRING ds_default_auth;
#ifdef HAVE_SMEM
static DYNAMIC_STRING ds_shm;
#endif
@@ -5335,7 +5802,8 @@ void do_connect(struct st_command *command)
{ "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" },
{ "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" },
{ "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" },
- { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" }
+ { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" },
+ { "default_auth", ARG_STRING, FALSE, &ds_default_auth, "Default authentication to use" }
};
DBUG_ENTER("do_connect");
@@ -5420,16 +5888,20 @@ void do_connect(struct st_command *command)
if (!(con_slot= find_connection_by_name("-closed_connection-")))
die("Connection limit exhausted, you can have max %d connections",
opt_max_connections);
- my_free(con_slot->name, MYF(0));
+ my_free(con_slot->name);
con_slot->name= 0;
}
-#ifdef EMBEDDED_LIBRARY
- con_slot->query_done= 1;
- con_slot->has_thread= FALSE;
-#endif
+ init_connection_thd(con_slot);
+
if (!(con_slot->mysql= mysql_init(0)))
die("Failed on mysql_init()");
+
+ if (opt_connect_timeout)
+ mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
+ (void *) &opt_connect_timeout);
+
+ mysql_options(con_slot->mysql, MYSQL_OPT_NONBLOCK, 0);
if (opt_compress || con_compress)
mysql_options(con_slot->mysql, MYSQL_OPT_COMPRESS, NullS);
mysql_options(con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
@@ -5438,18 +5910,14 @@ void do_connect(struct st_command *command)
if (opt_charsets_dir)
mysql_options(con_slot->mysql, MYSQL_SET_CHARSET_DIR,
opt_charsets_dir);
- if (opt_connect_timeout >= 0)
- mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
- &opt_connect_timeout);
-
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (opt_use_ssl)
con_ssl= 1;
#endif
if (con_ssl)
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
mysql_ssl_set(con_slot->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
#if MYSQL_VERSION_ID >= 50000
@@ -5491,6 +5959,12 @@ void do_connect(struct st_command *command)
if (ds_database.length == 0)
dynstr_set(&ds_database, opt_db);
+ if (opt_plugin_dir && *opt_plugin_dir)
+ mysql_options(con_slot->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
+
+ if (ds_default_auth.length)
+ mysql_options(con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str);
+
/* Special database to allow one to connect without a database name */
if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*"))
dynstr_set(&ds_database, "");
@@ -5519,6 +5993,7 @@ void do_connect(struct st_command *command)
dynstr_free(&ds_port);
dynstr_free(&ds_sock);
dynstr_free(&ds_options);
+ dynstr_free(&ds_default_auth);
#ifdef HAVE_SMEM
dynstr_free(&ds_shm);
#endif
@@ -5558,6 +6033,40 @@ int do_done(struct st_command *command)
return 0;
}
+/* Operands available in if or while conditions */
+
+enum block_op {
+ EQ_OP,
+ NE_OP,
+ GT_OP,
+ GE_OP,
+ LT_OP,
+ LE_OP,
+ ILLEG_OP
+};
+
+
+enum block_op find_operand(const char *start)
+{
+ char first= *start;
+ char next= *(start+1);
+
+ if (first == '=' && next == '=')
+ return EQ_OP;
+ if (first == '!' && next == '=')
+ return NE_OP;
+ if (first == '>' && next == '=')
+ return GE_OP;
+ if (first == '>')
+ return GT_OP;
+ if (first == '<' && next == '=')
+ return LE_OP;
+ if (first == '<')
+ return LT_OP;
+
+ return ILLEG_OP;
+}
+
/*
Process start of a "if" or "while" statement
@@ -5583,6 +6092,13 @@ int do_done(struct st_command *command)
A '!' can be used before the <expr> to indicate it should
be executed if it evaluates to zero.
+ <expr> can also be a simple comparison condition:
+
+ <variable> <op> <expr>
+
+ The left hand side must be a variable, the right hand side can be a
+ variable, number, string or `query`. Operands are ==, !=, <, <=, >, >=.
+ == and != can be used for strings, all can be used for numerical values.
*/
void do_block(enum block_cmd cmd, struct st_command* command)
@@ -5618,6 +6134,9 @@ void do_block(enum block_cmd cmd, struct st_command* command)
if (!expr_start++)
die("missing '(' in %s", cmd_name);
+ while (my_isspace(charset_info, *expr_start))
+ expr_start++;
+
/* Check for !<expr> */
if (*expr_start == '!')
{
@@ -5638,14 +6157,110 @@ void do_block(enum block_cmd cmd, struct st_command* command)
die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
var_init(&v,0,0,0,0);
- eval_expr(&v, expr_start, &expr_end);
+ /* If expression starts with a variable, it may be a compare condition */
+
+ if (*expr_start == '$')
+ {
+ const char *curr_ptr= expr_end;
+ eval_expr(&v, expr_start, &curr_ptr, true);
+ while (my_isspace(charset_info, *++curr_ptr))
+ {}
+ /* If there was nothing past the variable, skip condition part */
+ if (curr_ptr == expr_end)
+ goto NO_COMPARE;
+
+ enum block_op operand= find_operand(curr_ptr);
+ if (operand == ILLEG_OP)
+ die("Found junk '%.*s' after $variable in condition",
+ (int)(expr_end - curr_ptr), curr_ptr);
+
+ /* We could silently allow this, but may be confusing */
+ if (not_expr)
+ die("Negation and comparison should not be combined, please rewrite");
+
+ /* Skip the 1 or 2 chars of the operand, then white space */
+ if (operand == LT_OP || operand == GT_OP)
+ {
+ curr_ptr++;
+ }
+ else
+ {
+ curr_ptr+= 2;
+ }
+ while (my_isspace(charset_info, *curr_ptr))
+ curr_ptr++;
+ if (curr_ptr == expr_end)
+ die("Missing right operand in comparison");
+
+ /* Strip off trailing white space */
+ while (my_isspace(charset_info, expr_end[-1]))
+ expr_end--;
+ /* strip off ' or " around the string */
+ if (*curr_ptr == '\'' || *curr_ptr == '"')
+ {
+ if (expr_end[-1] != *curr_ptr)
+ die("Unterminated string value");
+ curr_ptr++;
+ expr_end--;
+ }
+ VAR v2;
+ var_init(&v2,0,0,0,0);
+ eval_expr(&v2, curr_ptr, &expr_end);
+
+ if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int))
+ die("Only == and != are supported for string values");
+
+ /* Now we overwrite the first variable with 0 or 1 (for false or true) */
+
+ switch (operand)
+ {
+ case EQ_OP:
+ if (v.is_int)
+ v.int_val= (v2.is_int && v2.int_val == v.int_val);
+ else
+ v.int_val= !strcmp (v.str_val, v2.str_val);
+ break;
+
+ case NE_OP:
+ if (v.is_int)
+ v.int_val= ! (v2.is_int && v2.int_val == v.int_val);
+ else
+ v.int_val= (strcmp (v.str_val, v2.str_val) != 0);
+ break;
+
+ case LT_OP:
+ v.int_val= (v.int_val < v2.int_val);
+ break;
+ case LE_OP:
+ v.int_val= (v.int_val <= v2.int_val);
+ break;
+ case GT_OP:
+ v.int_val= (v.int_val > v2.int_val);
+ break;
+ case GE_OP:
+ v.int_val= (v.int_val >= v2.int_val);
+ break;
+ case ILLEG_OP:
+ die("Impossible operator, this cannot happen");
+ }
+
+ v.is_int= TRUE;
+ var_free(&v2);
+ } else
+ {
+ if (*expr_start != '`' && ! my_isdigit(charset_info, *expr_start))
+ die("Expression in if/while must beging with $, ` or a number");
+ eval_expr(&v, expr_start, &expr_end);
+ }
+
+ NO_COMPARE:
/* Define inner block */
cur_block++;
cur_block->cmd= cmd;
- if (v.int_val)
+ if (v.is_int)
{
- cur_block->ok= TRUE;
+ cur_block->ok= (v.int_val != 0);
} else
/* Any non-empty string which does not begin with 0 is also TRUE */
{
@@ -5753,7 +6368,7 @@ my_bool end_of_query(int c)
int read_line(char *buf, int size)
{
- char c, UNINIT_VAR(last_quote);
+ char c, UNINIT_VAR(last_quote), last_char= 0;
char *p= buf, *buf_end= buf + size - 1;
int skip_char= 0;
my_bool have_slash= FALSE;
@@ -5776,7 +6391,7 @@ int read_line(char *buf, int size)
fclose(cur_file->file);
cur_file->file= 0;
}
- my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(cur_file->file_name);
cur_file->file_name= 0;
if (cur_file == file_stack)
{
@@ -5857,14 +6472,24 @@ int read_line(char *buf, int size)
}
else if (my_isspace(charset_info, c))
{
- /* Skip all space at begining of line */
if (c == '\n')
{
+ if (last_char == '\n')
+ {
+ /* Two new lines in a row, return empty line */
+ DBUG_PRINT("info", ("Found two new lines in a row"));
+ *p++= c;
+ *p= 0;
+ DBUG_RETURN(0);
+ }
+
/* Query hasn't started yet */
start_lineno= cur_file->lineno;
DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d",
start_lineno));
}
+
+ /* Skip all space at begining of line */
skip_char= 1;
}
else if (end_of_query(c))
@@ -5905,6 +6530,8 @@ int read_line(char *buf, int size)
}
+ last_char= c;
+
if (!skip_char)
{
/* Could be a multibyte character */
@@ -5940,7 +6567,7 @@ int read_line(char *buf, int size)
*p++= c;
}
}
- die("The input buffer is too small for this query.x\n" \
+ die("The input buffer is too small for this query.x\n" \
"check your query or increase MAX_QUERY and recompile");
DBUG_RETURN(0);
}
@@ -6114,9 +6741,10 @@ int read_command(struct st_command** command_ptr)
DBUG_RETURN(1);
}
- convert_to_format_v1(read_command_buf);
+ if (opt_result_format_version == 1)
+ convert_to_format_v1(read_command_buf);
- DBUG_PRINT("info", ("query: %s", read_command_buf));
+ DBUG_PRINT("info", ("query: '%s'", read_command_buf));
if (*p == '#')
{
command->type= Q_COMMENT;
@@ -6126,6 +6754,10 @@ int read_command(struct st_command** command_ptr)
command->type= Q_COMMENT_WITH_COMMAND;
p+= 2; /* Skip past -- */
}
+ else if (*p == '\n')
+ {
+ command->type= Q_EMPTY_LINE;
+ }
/* Skip leading spaces */
while (*p && my_isspace(charset_info, *p))
@@ -6162,13 +6794,19 @@ static struct my_option my_long_options[] =
0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Basedir for tests.", &opt_basedir,
&opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"character-sets-dir", OPT_CHARSETS_DIR,
+ {"character-sets-dir", 0,
"Directory for character set files.", &opt_charsets_dir,
&opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"compress", 'C', "Use the compressed server/client protocol.",
&opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
- {"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statements.",
+ {"continue-on-error", 0,
+ "Continue test even if we got an error. "
+ "This is mostly useful when testing a storage engine to see what from a test file it can execute, "
+ "or to find all syntax errors in a newly created big test file",
+ &opt_continue_on_error, &opt_continue_on_error, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"cursor-protocol", 0, "Use cursors for prepared statements.",
&cursor_protocol, &cursor_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"database", 'D', "Database to use.", &opt_db, &opt_db, 0,
@@ -6180,32 +6818,27 @@ static struct my_option my_long_options[] =
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
+ {"debug-check", 0, "Check memory and open file usage at exit.",
&debug_check_flag, &debug_check_flag, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
+ {"debug-info", 0, "Print some debug info at exit.",
&debug_info_flag, &debug_info_flag,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"global-subst", OPT_GLOBAL_SUBST, "argument should be 'X,Y' ;"
- " substitute string X with another Y accross the whole test's current"
- " result before comparing with expected result file",
- &global_subst, &global_subst, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", &opt_host, &opt_host, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"include", 'i', "Include SQL before each test case.", &opt_include,
- &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"prologue", 0, "Include SQL before each test case.", &opt_prologue,
+ &opt_prologue, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"logdir", OPT_LOG_DIR, "Directory for log files", &opt_logdir,
&opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"mark-progress", OPT_MARK_PROGRESS,
+ {"mark-progress", 0,
"Write line number and elapsed time to <testname>.progress.",
&opt_mark_progress, &opt_mark_progress, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
+ {"max-connect-retries", 0,
"Maximum number of attempts to connect to server.",
&opt_max_connect_retries, &opt_max_connect_retries, 0,
GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
- {"max-connections", OPT_MAX_CONNECTIONS,
+ {"max-connections", 0,
"Max number of open connections to server",
&opt_max_connections, &opt_max_connections, 0,
GET_INT, REQUIRED_ARG, DEFAULT_MAX_CONN, 8, 5120, 0, 0, 0},
@@ -6220,10 +6853,14 @@ static struct my_option my_long_options[] =
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&opt_port, &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"ps-protocol", OPT_PS_PROTOCOL,
+ {"ps-protocol", 0,
"Use prepared-statement protocol for communication.",
&ps_protocol, &ps_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"non-blocking-api", 0,
+ "Use the non-blocking client API for communication.",
+ &non_blocking_api_enabled, &non_blocking_api_enabled, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"quiet", 's', "Suppress all normal output.", &silent,
&silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"record", 'r', "Record output of test_file into result file.",
@@ -6231,40 +6868,37 @@ static struct my_option my_long_options[] =
{"result-file", 'R', "Read/store result from/in this file.",
&result_file_name, &result_file_name, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"result-format-version", OPT_RESULT_FORMAT_VERSION,
+ "Version of the result file format to use",
+ &opt_result_format_version,
+ &opt_result_format_version, 0,
+ GET_INT, REQUIRED_ARG, 1, 1, 2, 0, 0, 0},
{"server-arg", 'A', "Send option value to embedded server as a parameter.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"server-file", 'F', "Read embedded server arguments from file.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef HAVE_SMEM
- {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
+ {"shared-memory-base-name", 0,
"Base name of shared memory.", &shared_memory_base_name,
&shared_memory_base_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
-#endif
{"silent", 's', "Suppress all normal output. Synonym for --quiet.",
&silent, &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
- "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- 0, 0, 0, 0, 0, 0},
{"sleep", 'T', "Always sleep this many seconds on sleep commands.",
&opt_sleep, &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
0, 0, 0},
{"socket", 'S', "The socket file to use for connection.",
&unix_sock, &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
- {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select.",
+ {"sp-protocol", 0, "Use stored procedures for select.",
&sp_protocol, &sp_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#include "sslopt-longopts.h"
- {"tail-lines", OPT_TAIL_LINES,
+ {"tail-lines", 0,
"Number of lines of the result to include in a failure report.",
&opt_tail_lines, &opt_tail_lines, 0,
GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
{"test-file", 'x', "Read test from/in this file (default stdin).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"connect-timeout", OPT_MY_CONNECT_TIMEOUT, "Client connection timeout",
- (uchar**) &opt_connect_timeout, (uchar**) &opt_connect_timeout, 0,
- GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0},
{"timer-file", 'm', "File where the timing in microseconds is stored.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"tmpdir", 't', "Temporary directory where sockets are put.",
@@ -6275,22 +6909,24 @@ static struct my_option my_long_options[] =
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select.",
+ {"view-protocol", 0, "Use views for select.",
&view_protocol, &view_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
- (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"default_auth", OPT_PLUGIN_DIR,
- "Default authentication client-side plugin to use.",
- (uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0,
+ {"connect_timeout", 0,
+ "Number of seconds before connection timeout.",
+ &opt_connect_timeout, &opt_connect_timeout, 0, GET_UINT, REQUIRED_ARG,
+ 120, 0, 3600 * 12, 0, 0, 0},
+ {"plugin_dir", 0, "Directory for client-side plugins.",
+ &opt_plugin_dir, &opt_plugin_dir, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"overlay-dir", 0, "Overlay directory.", &opt_overlay_dir,
+ &opt_overlay_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"suite-dir", 0, "Suite directory.", &opt_suite_dir,
+ &opt_suite_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
-#include <help_start.h>
-
void print_version(void)
{
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
@@ -6309,8 +6945,6 @@ void usage()
my_print_variables(my_long_options);
}
-#include <help_end.h>
-
/*
Read arguments for embedded server and put them into
@@ -6359,8 +6993,7 @@ void read_embedded_server_arguments(const char *name)
static my_bool
-get_one_option(int optid, const struct my_option *opt,
- char *argument)
+get_one_option(int optid, const struct my_option *opt, char *argument)
{
switch(optid) {
case '#':
@@ -6408,7 +7041,7 @@ get_one_option(int optid, const struct my_option *opt,
argument= (char*) ""; // Don't require password
if (argument)
{
- my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_pass);
opt_pass= my_strdup(argument, MYF(MY_FAE));
while (*argument) *argument++= 'x'; /* Destroy argument */
tty_password= 0;
@@ -6441,10 +7074,8 @@ get_one_option(int optid, const struct my_option *opt,
case 'F':
read_embedded_server_arguments(argument);
break;
- case OPT_SKIP_SAFEMALLOC:
-#ifdef SAFEMALLOC
- sf_malloc_quick=1;
-#endif
+ case OPT_RESULT_FORMAT_VERSION:
+ set_result_format_version(opt_result_format_version);
break;
case 'V':
print_version();
@@ -6465,7 +7096,9 @@ get_one_option(int optid, const struct my_option *opt,
int parse_args(int argc, char **argv)
{
- load_defaults("my",load_default_groups,&argc,&argv);
+ if (load_defaults("my",load_default_groups,&argc,&argv))
+ exit(1);
+
default_argv= argv;
if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
@@ -6495,11 +7128,17 @@ int parse_args(int argc, char **argv)
memcpy(global_subst_to, comma+1, strlen(comma));
}
+ if (!opt_suite_dir)
+ opt_suite_dir= "./";
+ suite_dir_len= strlen(opt_suite_dir);
+ overlay_dir_len= opt_overlay_dir ? strlen(opt_overlay_dir) : 0;
+
if (!record)
{
/* Check that the result file exists */
if (result_file_name && access(result_file_name, F_OK) != 0)
- die("The specified result file '%s' does not exist", result_file_name);
+ die("The specified result file '%s' does not exist",
+ result_file_name);
}
return 0;
@@ -6588,6 +7227,8 @@ void init_win_path_patterns()
"$MYSQL_TMP_DIR",
"$MYSQLTEST_VARDIR",
"$MASTER_MYSOCK",
+ "$MYSQL_SHAREDIR",
+ "$MYSQL_LIBDIR",
"./test/" };
int num_paths= sizeof(paths)/sizeof(char*);
int i;
@@ -6612,7 +7253,7 @@ void init_win_path_patterns()
/* Don't insert zero length strings in patterns array */
if (strlen(p) == 0)
{
- my_free(p, MYF(0));
+ my_free(p);
continue;
}
@@ -6636,7 +7277,7 @@ void free_win_path_patterns()
for (i=0 ; i < patterns.elements ; i++)
{
const char** pattern= dynamic_element(&patterns, i, const char**);
- my_free((char*) *pattern, MYF(0));
+ my_free((void *) *pattern);
}
delete_dynamic(&patterns);
}
@@ -6824,8 +7465,8 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
}
if (error != MYSQL_NO_DATA)
- die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: error: %d",
- error);
+ die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: "
+ "error: %d", error);
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
@@ -6833,12 +7474,12 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
for (i= 0; i < num_fields; i++)
{
/* Free data for output */
- my_free(my_bind[i].buffer, MYF(MY_WME | MY_FAE));
+ my_free(my_bind[i].buffer);
}
/* Free array with bind structs, lengths and NULL flags */
- my_free(my_bind , MYF(MY_WME | MY_FAE));
- my_free(length , MYF(MY_WME | MY_FAE));
- my_free(is_null , MYF(MY_WME | MY_FAE));
+ my_free(my_bind);
+ my_free(length);
+ my_free(is_null);
}
@@ -7023,21 +7664,13 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
/*
Send the query
*/
- if (do_send_query(cn, query, query_len, flags))
+ if (do_send_query(cn, query, query_len))
{
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), ds);
goto end;
}
}
-#ifdef EMBEDDED_LIBRARY
- /*
- Here we handle 'reap' command, so we need to check if the
- query's thread was finished and probably wait
- */
- else if (flags & QUERY_REAP_FLAG)
- wait_query_thread_end(cn);
-#endif /*EMBEDDED_LIBRARY*/
if (!(flags & QUERY_REAP_FLAG))
{
cn->pending= TRUE;
@@ -7050,7 +7683,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
When on first result set, call mysql_read_query_result to retrieve
answer to the query sent earlier
*/
- if ((counter==0) && mysql_read_query_result(mysql))
+ if ((counter==0) && do_read_query_result(cn))
{
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), ds);
@@ -7070,8 +7703,6 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
if (!disable_result_log)
{
- ulonglong UNINIT_VAR(affected_rows); /* Ok to be undef if 'disable_info' is set */
-
if (res)
{
MYSQL_FIELD *fields= mysql_fetch_fields(res);
@@ -7088,10 +7719,10 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
/*
Need to call mysql_affected_rows() before the "new"
- query to find the warnings
+ query to find the warnings.
*/
if (!disable_info)
- affected_rows= mysql_affected_rows(mysql);
+ append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
/*
Add all warnings to the result. We can't do this if we are in
@@ -7106,9 +7737,6 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
}
}
-
- if (!disable_info)
- append_info(ds, affected_rows, mysql_info(mysql));
}
if (res)
@@ -7129,6 +7757,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
/* If we come here the query is both executed and read successfully */
handle_no_error(command);
+ revert_properties();
end:
@@ -7181,7 +7810,8 @@ static int match_expected_error(struct st_command *command,
NULL is quite likely, but not in conjunction with a SQL-state expect!
*/
if (unlikely(err_sqlstate == NULL))
- die("expecting a SQL-state (%s) from query '%s' which cannot produce one...",
+ die("expecting a SQL-state (%s) from query '%s' which cannot "
+ "produce one...",
command->expected_errors.err[i].code.sqlstate, command->query);
if (strncmp(command->expected_errors.err[i].code.sqlstate,
@@ -7235,7 +7865,11 @@ void handle_error(struct st_command *command,
}
if (command->abort_on_error)
- die("query '%s' failed: %d: %s", command->query, err_errno, err_error);
+ {
+ report_or_die("query '%s' failed: %d: %s", command->query, err_errno,
+ err_error);
+ DBUG_VOID_RETURN;
+ }
DBUG_PRINT("info", ("expected_errors.count: %d",
command->expected_errors.count));
@@ -7262,6 +7896,7 @@ void handle_error(struct st_command *command,
dynstr_append(ds,"Got one of the listed errors\n");
}
/* OK */
+ revert_properties();
DBUG_VOID_RETURN;
}
@@ -7280,15 +7915,18 @@ void handle_error(struct st_command *command,
if (command->expected_errors.count > 0)
{
if (command->expected_errors.err[0].type == ERR_ERRNO)
- die("query '%s' failed with wrong errno %d: '%s', instead of %d...",
- command->query, err_errno, err_error,
- command->expected_errors.err[0].code.errnum);
+ report_or_die("query '%s' failed with wrong errno %d: '%s', instead of "
+ "%d...",
+ command->query, err_errno, err_error,
+ command->expected_errors.err[0].code.errnum);
else
- die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
- command->query, err_sqlstate, err_error,
- command->expected_errors.err[0].code.sqlstate);
+ report_or_die("query '%s' failed with wrong sqlstate %s: '%s', "
+ "instead of %s...",
+ command->query, err_sqlstate, err_error,
+ command->expected_errors.err[0].code.sqlstate);
}
+ revert_properties();
DBUG_VOID_RETURN;
}
@@ -7312,17 +7950,18 @@ void handle_no_error(struct st_command *command)
command->expected_errors.err[0].code.errnum != 0)
{
/* Error code we wanted was != 0, i.e. not an expected success */
- die("query '%s' succeeded - should have failed with errno %d...",
- command->query, command->expected_errors.err[0].code.errnum);
+ report_or_die("query '%s' succeeded - should have failed with errno %d...",
+ command->query, command->expected_errors.err[0].code.errnum);
}
else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
{
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
- die("query '%s' succeeded - should have failed with sqlstate %s...",
- command->query, command->expected_errors.err[0].code.sqlstate);
+ report_or_die("query '%s' succeeded - should have failed with "
+ "sqlstate %s...",
+ command->query,
+ command->expected_errors.err[0].code.sqlstate);
}
-
DBUG_VOID_RETURN;
}
@@ -7450,9 +8089,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
handle_no_error(command);
if (!disable_result_log)
{
- ulonglong affected_rows;
- LINT_INIT(affected_rows);
-
/*
Not all statements creates a result set. If there is one we can
now create another normal result set that contains the meta
@@ -7495,11 +8131,11 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
}
/*
- Need to grab affected rows information before getting
- warnings here
+ Fetch info before fetching warnings, since it will be reset
+ otherwise.
*/
if (!disable_info)
- affected_rows= mysql_affected_rows(mysql);
+ append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql));
if (!disable_warnings)
{
@@ -7523,8 +8159,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
ds_execute_warnings.length);
}
}
- if (!disable_info)
- append_info(ds, affected_rows, mysql_info(mysql));
}
end:
@@ -7542,6 +8176,8 @@ end:
var_set_errno(mysql_stmt_errno(stmt));
+ revert_properties();
+
/* Close the statement if reconnect, need new prepare */
if (mysql->reconnect)
{
@@ -7572,8 +8208,13 @@ int util_query(MYSQL* org_mysql, const char* query){
if (!(mysql= mysql_init(mysql)))
die("Failed in mysql_init()");
+ if (opt_connect_timeout)
+ mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT,
+ (void *) &opt_connect_timeout);
+
/* enable local infile, in non-binary builds often disabled by default */
mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0);
+ mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
safe_connect(mysql, "util", org_mysql->host, org_mysql->user,
org_mysql->passwd, org_mysql->db, org_mysql->port,
org_mysql->unix_socket);
@@ -7617,12 +8258,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
DBUG_ENTER("run_query");
if (cn->pending && (flags & QUERY_SEND_FLAG))
- die ("Cannot run query on connection between send and reap");
+ die("Cannot run query on connection between send and reap");
if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
- die ("Cannot reap on a connection without pending send");
+ die("Cannot reap on a connection without pending send");
init_dynamic_string(&ds_warnings, NULL, 0, 256);
+ ds_warn= &ds_warnings;
+
/*
Evaluate query if this is an eval command
*/
@@ -7788,7 +8431,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
ds, &ds_warnings);
dynstr_free(&ds_warnings);
- if (command->type == Q_EVAL)
+ ds_warn= 0;
+ if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
dynstr_free(&eval_query);
if (display_result_sorted)
@@ -7802,13 +8446,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
if (sp_created)
{
if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
- die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql));
+ report_or_die("Failed to drop sp: %d: %s", mysql_errno(mysql),
+ mysql_error(mysql));
}
if (view_created)
{
if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
- die("Failed to drop view: %d: %s",
+ report_or_die("Failed to drop view: %d: %s",
mysql_errno(mysql), mysql_error(mysql));
}
@@ -7834,8 +8479,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
char *re_eprint(int err)
{
static char epbuf[100];
- size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL,
- epbuf, sizeof(epbuf));
+ size_t len __attribute__((unused))=
+ my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf));
assert(len <= sizeof(epbuf));
return(epbuf);
}
@@ -7944,7 +8589,7 @@ void get_command_type(struct st_command* command)
save= command->query[command->first_word_len];
command->query[command->first_word_len]= 0;
- type= find_type(command->query, &command_typelib, 1+2);
+ type= find_type(command->query, &command_typelib, FIND_TYPE_NO_PREFIX);
command->query[command->first_word_len]= save;
if (type > 0)
{
@@ -7972,9 +8617,10 @@ void get_command_type(struct st_command* command)
else
{
/* -- "comment" that didn't contain a mysqltest command */
- die("Found line beginning with -- that didn't contain "\
- "a valid mysqltest command, check your syntax or "\
+ report_or_die("Found line beginning with -- that didn't contain " \
+ "a valid mysqltest command, check your syntax or " \
"use # if you intended to write a comment");
+ command->type= Q_COMMENT;
}
}
@@ -8044,14 +8690,17 @@ static void dump_backtrace(void)
fprintf(stderr, "read_command_buf (%p): ", read_command_buf);
my_safe_print_str(read_command_buf, sizeof(read_command_buf));
+ fputc('\n', stderr);
if (conn)
{
fprintf(stderr, "conn->name (%p): ", conn->name);
my_safe_print_str(conn->name, conn->name_len);
+ fputc('\n', stderr);
#ifdef EMBEDDED_LIBRARY
fprintf(stderr, "conn->cur_query (%p): ", conn->cur_query);
my_safe_print_str(conn->cur_query, conn->cur_query_len);
+ fputc('\n', stderr);
#endif
}
fputs("Attempting backtrace...\n", stderr);
@@ -8156,6 +8805,9 @@ int main(int argc, char **argv)
MY_INIT(argv[0]);
DBUG_ENTER("main");
+ /* mysqltest has no way to free all its memory correctly */
+ sf_leaking_memory= 1;
+
save_file[0]= 0;
TMPDIR[0]= 0;
@@ -8186,7 +8838,7 @@ int main(int argc, char **argv)
my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024);
- if (hash_init2(&var_hash, 64, charset_info,
+ if (my_hash_init2(&var_hash, 64, charset_info,
128, 0, 0, get_var_key, var_free, MYF(0)))
die("Variable hash initialization failed");
@@ -8234,6 +8886,7 @@ int main(int argc, char **argv)
next_con= connections + 1;
var_set_int("$PS_PROTOCOL", ps_protocol);
+ var_set_int("$NON_BLOCKING_API", non_blocking_api_enabled);
var_set_int("$SP_PROTOCOL", sp_protocol);
var_set_int("$VIEW_PROTOCOL", view_protocol);
var_set_int("$CURSOR_PROTOCOL", cursor_protocol);
@@ -8261,6 +8914,7 @@ int main(int argc, char **argv)
cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
cur_file->lineno= 1;
}
+ var_set_string("MYSQLTEST_FILE", cur_file->file_name);
init_re();
/* Cursor protcol implies ps protocol */
@@ -8273,8 +8927,12 @@ int main(int argc, char **argv)
cursor_protocol_enabled= cursor_protocol;
st_connection *con= connections;
+ init_connection_thd(con);
if (! (con->mysql= mysql_init(0)))
die("Failed in mysql_init()");
+ if (opt_connect_timeout)
+ mysql_options(con->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
+ (void *) &opt_connect_timeout);
if (opt_compress)
mysql_options(con->mysql,MYSQL_OPT_COMPRESS,NullS);
mysql_options(con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
@@ -8290,10 +8948,7 @@ int main(int argc, char **argv)
if (opt_plugin_dir && *opt_plugin_dir)
mysql_options(con->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
- if (opt_default_auth && *opt_default_auth)
- mysql_options(con->mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
-
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (opt_use_ssl)
{
@@ -8315,6 +8970,7 @@ int main(int argc, char **argv)
if (!(con->name = my_strdup("default", MYF(MY_WME))))
die("Out of memory");
+ mysql_options(con->mysql, MYSQL_OPT_NONBLOCK, 0);
safe_connect(con->mysql, con->name, opt_host, opt_user, opt_pass,
opt_db, opt_port, unix_sock);
@@ -8331,9 +8987,9 @@ int main(int argc, char **argv)
set_current_connection(con);
- if (opt_include)
+ if (opt_prologue)
{
- open_file(opt_include);
+ open_file(opt_prologue);
}
verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name);
@@ -8399,66 +9055,49 @@ int main(int argc, char **argv)
case Q_DISCONNECT:
case Q_DIRTY_CLOSE:
do_close_connection(command); break;
- case Q_RPL_PROBE: do_rpl_probe(command); break;
- case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(command); break;
- case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(command); break;
case Q_ENABLE_PREPARE_WARNINGS: prepare_warnings_enabled=1; break;
case Q_DISABLE_PREPARE_WARNINGS: prepare_warnings_enabled=0; break;
case Q_ENABLE_QUERY_LOG:
- disable_query_log= 0;
- var_set_int("$ENABLED_QUERY_LOG", 1);
+ set_property(command, P_QUERY, 0);
break;
case Q_DISABLE_QUERY_LOG:
- disable_query_log= 1;
- var_set_int("$ENABLED_QUERY_LOG", 0);
+ set_property(command, P_QUERY, 1);
break;
case Q_ENABLE_ABORT_ON_ERROR:
- abort_on_error= 1;
- var_set_int("$ENABLED_ABORT_ON_ERROR", 1);
+ set_property(command, P_ABORT, 1);
break;
case Q_DISABLE_ABORT_ON_ERROR:
- abort_on_error= 0;
- var_set_int("$ENABLED_ABORT_ON_ERROR", 0);
+ set_property(command, P_ABORT, 0);
break;
case Q_ENABLE_RESULT_LOG:
- disable_result_log= 0;
- var_set_int("$ENABLED_RESULT_LOG", 1);
+ set_property(command, P_RESULT, 0);
break;
case Q_DISABLE_RESULT_LOG:
- disable_result_log=1;
- var_set_int("$ENABLED_RESULT_LOG", 0);
+ set_property(command, P_RESULT, 1);
break;
case Q_ENABLE_CONNECT_LOG:
- disable_connect_log=0;
- var_set_int("$ENABLED_CONNECT_LOG", 1);
+ set_property(command, P_CONNECT, 0);
break;
case Q_DISABLE_CONNECT_LOG:
- disable_connect_log=1;
- var_set_int("$ENABLED_CONNECT_LOG", 0);
+ set_property(command, P_CONNECT, 1);
break;
case Q_ENABLE_WARNINGS:
- disable_warnings= 0;
- var_set_int("$ENABLED_WARNINGS", 1);
+ set_property(command, P_WARN, 0);
break;
case Q_DISABLE_WARNINGS:
- disable_warnings= 1;
- var_set_int("$ENABLED_WARNINGS", 0);
+ set_property(command, P_WARN, 1);
break;
case Q_ENABLE_INFO:
- disable_info= 0;
- var_set_int("$ENABLED_INFO", 1);
+ set_property(command, P_INFO, 0);
break;
case Q_DISABLE_INFO:
- disable_info= 1;
- var_set_int("$ENABLED_INFO", 0);
+ set_property(command, P_INFO, 1);
break;
case Q_ENABLE_METADATA:
- display_metadata= 1;
- var_set_int("$ENABLED_METADATA", 1);
+ set_property(command, P_META, 1);
break;
case Q_DISABLE_METADATA:
- display_metadata= 0;
- var_set_int("$ENABLED_METADATA", 0);
+ set_property(command, P_META, 0);
break;
case Q_ENABLE_COLUMN_NAMES:
disable_column_names= 0;
@@ -8498,6 +9137,7 @@ int main(int argc, char **argv)
case Q_MOVE_FILE: do_move_file(command); break;
case Q_CHMOD_FILE: do_chmod_file(command); break;
case Q_PERL: do_perl(command); break;
+ case Q_RESULT_FORMAT_VERSION: do_result_format_version(command); break;
case Q_DELIMITER:
do_delimiter(command);
break;
@@ -8624,9 +9264,38 @@ int main(int argc, char **argv)
do_sync_with_master2(command, 0);
break;
}
- case Q_COMMENT: /* Ignore row */
+ case Q_COMMENT:
+ {
command->last_argument= command->end;
+
+ /* Don't output comments in v1 */
+ if (opt_result_format_version == 1)
+ break;
+
+ /* Don't output comments if query logging is off */
+ if (disable_query_log)
+ break;
+
+ /* Write comment's with two starting #'s to result file */
+ const char* p= command->query;
+ if (p && *p == '#' && *(p+1) == '#')
+ {
+ dynstr_append_mem(&ds_res, command->query, command->query_len);
+ dynstr_append(&ds_res, "\n");
+ }
break;
+ }
+ case Q_EMPTY_LINE:
+ /* Don't output newline in v1 */
+ if (opt_result_format_version == 1)
+ break;
+
+ /* Don't output newline if query logging is off */
+ if (disable_query_log)
+ break;
+
+ dynstr_append(&ds_res, "\n");
+ break;
case Q_PING:
handle_command_error(command, mysql_ping(cur_con->mysql), -1);
break;
@@ -8654,12 +9323,18 @@ int main(int argc, char **argv)
do_set_charset(command);
break;
case Q_DISABLE_PS_PROTOCOL:
- ps_protocol_enabled= 0;
+ set_property(command, P_PS, 0);
/* Close any open statements */
close_statements();
break;
case Q_ENABLE_PS_PROTOCOL:
- ps_protocol_enabled= ps_protocol;
+ set_property(command, P_PS, ps_protocol);
+ break;
+ case Q_DISABLE_NON_BLOCKING_API:
+ non_blocking_api_enabled= 0;
+ break;
+ case Q_ENABLE_NON_BLOCKING_API:
+ non_blocking_api_enabled= 1;
break;
case Q_DISABLE_RECONNECT:
set_reconnect(cur_con->mysql, 0);
@@ -8673,7 +9348,7 @@ int main(int argc, char **argv)
if (parsing_disabled == 0)
parsing_disabled= 1;
else
- die("Parsing is already disabled");
+ report_or_die("Parsing is already disabled");
break;
case Q_ENABLE_PARSING:
/*
@@ -8683,7 +9358,7 @@ int main(int argc, char **argv)
if (parsing_disabled == 1)
parsing_disabled= 0;
else
- die("Parsing is already enabled");
+ report_or_die("Parsing is already enabled");
break;
case Q_DIE:
/* Abort test with error code and error message */
@@ -8887,13 +9562,14 @@ void do_get_replace_column(struct st_command *command)
if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
die("Wrong column number to replace_column in '%s'", command->query);
if (!*from)
- die("Wrong number of arguments to replace_column in '%s'", command->query);
+ die("Wrong number of arguments to replace_column in '%s'",
+ command->query);
to= get_string(&buff, &from, command);
- my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR);
+ my_free(replace_column[column_number-1]);
replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
set_if_bigger(max_replace_column, column_number);
}
- my_free(start, MYF(0));
+ my_free(start);
command->last_argument= command->end;
DBUG_VOID_RETURN;
@@ -8907,7 +9583,7 @@ void free_replace_column()
{
if (replace_column[i])
{
- my_free(replace_column[i], 0);
+ my_free(replace_column[i]);
replace_column[i]= 0;
}
}
@@ -8925,20 +9601,15 @@ void free_replace_column()
typedef struct st_pointer_array { /* when using array-strings */
TYPELIB typelib; /* Pointer to strings */
uchar *str; /* Strings is here */
- int7 *flag; /* Flag about each var. */
+ uint8 *flag; /* Flag about each var. */
uint array_allocs,max_count,length,max_length;
} POINTER_ARRAY;
-struct st_replace;
struct st_replace *init_replace(char * *from, char * *to, uint count,
char * word_end_chars);
int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name);
-void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds,
- const char *from, int len);
void free_pointer_array(POINTER_ARRAY *pa);
-struct st_replace *glob_replace;
-
/*
Get arguments for replace. The syntax is:
replace from to [from to ...]
@@ -8988,7 +9659,7 @@ void do_get_replace(struct st_command *command)
die("Can't initialize replace from '%s'", command->query);
free_pointer_array(&from_array);
free_pointer_array(&to_array);
- my_free(start, MYF(0));
+ my_free(start);
command->last_argument= command->end;
DBUG_VOID_RETURN;
}
@@ -8997,11 +9668,8 @@ void do_get_replace(struct st_command *command)
void free_replace()
{
DBUG_ENTER("free_replace");
- if (glob_replace)
- {
- my_free(glob_replace,MYF(0));
- glob_replace=0;
- }
+ my_free(glob_replace);
+ glob_replace= NULL;
DBUG_VOID_RETURN;
}
@@ -9085,26 +9753,6 @@ struct st_regex
int icase; /* true if the match is case insensitive */
};
-struct st_replace_regex
-{
- DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
-
- /*
- Temporary storage areas for substitutions. To reduce unnessary copying
- and memory freeing/allocation, we pre-allocate two buffers, and alternate
- their use, one for input/one for output, the roles changing on the next
- st_regex substition. At the end of substitutions buf points to the
- one containing the final result.
- */
- char* buf;
- char* even_buf;
- char* odd_buf;
- int even_buf_len;
- int odd_buf_len;
-};
-
-struct st_replace_regex *glob_replace_regex= 0;
-
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
char *string, int icase);
@@ -9221,7 +9869,7 @@ struct st_replace_regex* init_replace_regex(char* expr)
return res;
err:
- my_free(res,0);
+ my_free(res);
die("Error parsing replace_regex \"%s\"", expr);
return 0;
}
@@ -9303,7 +9951,13 @@ void do_get_replace_regex(struct st_command *command)
{
char *expr= command->first_argument;
free_replace_regex();
- if (!(glob_replace_regex=init_replace_regex(expr)))
+ /* Allow variable for the *entire* list of replacements */
+ if (*expr == '$')
+ {
+ VAR *val= var_get(expr, NULL, 0, 1);
+ expr= val ? val->str_val : NULL;
+ }
+ if (expr && *expr && !(glob_replace_regex=init_replace_regex(expr)))
die("Could not init replace_regex");
command->last_argument= command->end;
}
@@ -9313,9 +9967,9 @@ void free_replace_regex()
if (glob_replace_regex)
{
delete_dynamic(&glob_replace_regex->regex_arr);
- my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR));
- my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR));
- my_free(glob_replace_regex,MYF(0));
+ my_free(glob_replace_regex->even_buf);
+ my_free(glob_replace_regex->odd_buf);
+ my_free(glob_replace_regex);
glob_replace_regex=0;
}
}
@@ -9510,7 +10164,7 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
str_p= str_end;
}
}
- my_free(subs, MYF(0));
+ my_free(subs);
my_regfree(&r);
*res_p= 0;
*buf_p= buf;
@@ -9634,7 +10288,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count,
free_sets(&sets);
DBUG_RETURN(0);
}
- VOID(make_new_set(&sets)); /* Set starting set */
+ (void) make_new_set(&sets); /* Set starting set */
make_sets_invisible(&sets); /* Hide previus sets */
used_sets=-1;
word_states=make_new_set(&sets); /* Start of new word */
@@ -9642,7 +10296,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count,
if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
{
free_sets(&sets);
- my_free(found_set,MYF(0));
+ my_free(found_set);
DBUG_RETURN(0);
}
@@ -9836,9 +10490,9 @@ REPLACE *init_replace(char * *from, char * *to,uint count,
replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
}
}
- my_free(follow,MYF(0));
+ my_free(follow);
free_sets(&sets);
- my_free(found_set,MYF(0));
+ my_free(found_set);
DBUG_PRINT("exit",("Replace table has %d states",sets.count));
DBUG_RETURN(replace);
}
@@ -9854,7 +10508,7 @@ int init_sets(REP_SETS *sets,uint states)
if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
SET_MALLOC_HUNC,MYF(MY_WME))))
{
- my_free(sets->set,MYF(0));
+ my_free(sets->set);
return 1;
}
return 0;
@@ -9915,8 +10569,8 @@ void free_last_set(REP_SETS *sets)
void free_sets(REP_SETS *sets)
{
- my_free(sets->set_buffer,MYF(0));
- my_free(sets->bit_buffer,MYF(0));
+ my_free(sets->set_buffer);
+ my_free(sets->bit_buffer);
return;
}
@@ -10054,12 +10708,12 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name)
if (!(pa->str= (uchar*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
MYF(MY_WME))))
{
- my_free((char*) pa->typelib.type_names,MYF(0));
+ my_free(pa->typelib.type_names);
DBUG_RETURN (-1);
}
pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(uchar*)+
sizeof(*pa->flag));
- pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ pa->flag= (uint8*) (pa->typelib.type_names+pa->max_count);
pa->length=0;
pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
pa->array_allocs=1;
@@ -10095,14 +10749,14 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name)
pa->typelib.type_names=new_array;
old_count=pa->max_count;
pa->max_count=len/(sizeof(uchar*) + sizeof(*pa->flag));
- pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ pa->flag= (uint8*) (pa->typelib.type_names+pa->max_count);
memcpy((uchar*) pa->flag,(char *) (pa->typelib.type_names+old_count),
old_count*sizeof(*pa->flag));
}
pa->flag[pa->typelib.count]=0; /* Reset flag */
pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length;
pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
- VOID(strmov((char*) pa->str+pa->length,name));
+ (void) strmov((char*) pa->str+pa->length,name);
pa->length+=length;
DBUG_RETURN(0);
} /* insert_pointer_name */
@@ -10115,9 +10769,9 @@ void free_pointer_array(POINTER_ARRAY *pa)
if (pa->typelib.count)
{
pa->typelib.count=0;
- my_free((char*) pa->typelib.type_names,MYF(0));
+ my_free(pa->typelib.type_names);
pa->typelib.type_names=0;
- my_free(pa->str,MYF(0));
+ my_free(pa->str);
}
} /* free_pointer_array */